summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJinkun Jang <jinkun.jang@samsung.com>2013-03-16 21:00:43 +0900
committerJinkun Jang <jinkun.jang@samsung.com>2013-03-16 21:00:43 +0900
commit88c80d0a587b534ebea25022f0df578123d53a3b (patch)
tree06d5dde002e68d348c0eedf398fc1f88715ed18a
parente5e3eb94d3bd0736a12b96b0f55f654a4c1502b2 (diff)
downloaddata-provider-master-88c80d0a587b534ebea25022f0df578123d53a3b.tar.gz
data-provider-master-88c80d0a587b534ebea25022f0df578123d53a3b.tar.bz2
data-provider-master-88c80d0a587b534ebea25022f0df578123d53a3b.zip
sync with master
-rw-r--r--CMakeLists.txt97
-rw-r--r--LICENSE83
-rw-r--r--data-provider-master.desktop9
-rw-r--r--data-provider-master.manifest56
-rw-r--r--data/CMakeLists.txt2
-rw-r--r--data/abi.ini14
-rw-r--r--data/baltic.conf.ini30
-rwxr-xr-xdata/data-provider-master91
-rw-r--r--data/data-provider-master.service29
-rw-r--r--data/private.conf.ini30
-rw-r--r--data/resolution.ini10
-rw-r--r--include/abi.h24
-rw-r--r--include/buffer_handler.h162
-rw-r--r--include/client_life.h107
-rw-r--r--include/client_rpc.h27
-rw-r--r--include/conf.h160
-rw-r--r--include/critical_log.h23
-rw-r--r--include/dead_monitor.h20
-rw-r--r--include/debug.h44
-rw-r--r--include/fault_manager.h25
-rw-r--r--include/fb.h38
-rw-r--r--include/group.h65
-rw-r--r--include/instance.h216
-rw-r--r--include/io.h25
-rw-r--r--include/liveinfo.h33
-rw-r--r--include/main.h16
-rw-r--r--include/package.h127
-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.h36
-rw-r--r--include/server.h20
-rw-r--r--include/setting.h21
-rw-r--r--include/slave_life.h193
-rw-r--r--include/slave_rpc.h30
-rw-r--r--include/util.h37
-rw-r--r--include/xmonitor.h34
-rw-r--r--packaging/data-provider-master.spec104
-rw-r--r--pkgmgr_livebox/CMakeLists.txt31
-rw-r--r--pkgmgr_livebox/include/dlist.h43
-rw-r--r--pkgmgr_livebox/livebox.xml76
-rw-r--r--pkgmgr_livebox/src/dlist.c180
-rw-r--r--pkgmgr_livebox/src/service_register.c2537
-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.c153
-rw-r--r--src/buffer_handler.c1326
-rw-r--r--src/client_life.c791
-rw-r--r--src/client_rpc.c271
-rw-r--r--src/conf.c643
-rw-r--r--src/critical_log.c164
-rw-r--r--src/dead_monitor.c85
-rw-r--r--src/fault_manager.c363
-rw-r--r--src/fb.c281
-rw-r--r--src/group.c873
-rw-r--r--src/instance.c2596
-rw-r--r--src/io.c857
-rw-r--r--src/liveinfo.c195
-rw-r--r--src/main.c260
-rw-r--r--src/package.c1469
-rw-r--r--src/parser.c845
-rw-r--r--src/pkgmgr.c602
-rw-r--r--src/script_handler.c1317
-rw-r--r--src/server.c5572
-rw-r--r--src/setting.c106
-rw-r--r--src/slave_life.c1291
-rw-r--r--src/slave_rpc.c640
-rw-r--r--src/util.c476
-rw-r--r--src/xmonitor.c476
-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.c1795
-rw-r--r--util_liveinfo/src/node.c362
75 files changed, 29045 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..1393c21
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,97 @@
+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-x
+ ecore
+ evas
+ ecore-evas
+ com-core
+ heynoti
+ x11
+ libdri2
+ libdrm
+ libtbm
+ xfixes
+ dri2proto
+ xext
+ xdamage
+ pkgmgr
+ livebox-service
+)
+
+SET(PACKAGE "${PROJECT_NAME}")
+SET(CMAKE_C_FLAGS "-Wall -fpie -Winline -Werror -fno-builtin-malloc -fno-omit-frame-pointer -g")
+SET(CMAKE_EXE_LINKER_FLAGS "-pie")
+
+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("-DNDEBUG")
+#ADD_DEFINITIONS("-DFLOG")
+ADD_DEFINITIONS(${pkg_CFLAGS})
+ADD_DEFINITIONS(${pkg_LDFLAGS})
+
+ADD_EXECUTABLE(${PROJECT_NAME}
+ src/main.c
+ src/util.c
+ src/fault_manager.c
+ src/parser.c
+ src/conf.c
+ src/dead_monitor.c
+ src/group.c
+ src/fb.c
+ src/script_handler.c
+ src/buffer_handler.c
+ src/io.c
+ src/xmonitor.c
+ src/slave_life.c
+ src/slave_rpc.c
+ src/client_life.c
+ src/client_rpc.c
+ src/setting.c
+ src/package.c
+ src/instance.c
+ src/server.c
+ src/abi.c
+ src/critical_log.c
+ src/liveinfo.c
+ src/pkgmgr.c
+)
+
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkg_LDFLAGS} "-ldl")
+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/resolution.ini DESTINATION /usr/share/data-provider-master PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION /usr/share/license RENAME "${PROJECT_NAME}")
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE SETUID)
+
+# INCLUDE FOR BUILD & INSTALL .PO FILES
+ADD_SUBDIRECTORY(res)
+ADD_SUBDIRECTORY(data)
+ADD_SUBDIRECTORY(pkgmgr_livebox)
+ADD_SUBDIRECTORY(util_liveinfo)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..27daa90
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,83 @@
+Flora License
+
+Version 1.0, May, 2012
+
+http://www.tizenopensource.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 Compatibility Definition Document and passes the Compatibility Test Suite 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:
+
+You must give any other recipients of the Work or Derivative Works a copy of this License; and
+You must cause any modified files to carry prominent notices stating that You changed the files; and
+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
+If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the 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.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.
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.manifest b/data-provider-master.manifest
new file mode 100644
index 0000000..b3b7af7
--- /dev/null
+++ b/data-provider-master.manifest
@@ -0,0 +1,56 @@
+<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" />
+ </provide>
+ <request>
+ <smack request="sys-assert::core" type="rwxat" />
+ </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="/usr/bin/liveinfo" label="data-provider-master" exec_label="data-provider-master" />
+
+ <!-- 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" />
+
+ <!-- Init script -->
+ <filesystem path="/etc/rc.d/init.d/data-provider-master" label="_" exec_label="none" />
+ <filesystem path="/etc/rc.d/rc3.d/S99data-provider-master" label="_" exec_label="none" />
+ <filesystem path="/usr/lib/systemd/user/data-provider-master.service" label="_" />
+ <filesystem path="/usr/lib/systemd/user/tizen-middleware.target.wants/data-provider-master.service" label="_" />
+
+ <!-- Package manager plugin -->
+ <filesystem path="/usr/etc/package-manager/parserlib/liblivebox.so" label="_" />
+ </assign>
+</manifest>
diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt
new file mode 100644
index 0000000..772eac6
--- /dev/null
+++ b/data/CMakeLists.txt
@@ -0,0 +1,2 @@
+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)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/data/data-provider-master.service DESTINATION /usr/lib/systemd/user/ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
diff --git a/data/abi.ini b/data/abi.ini
new file mode 100644
index 0000000..8822699
--- /dev/null
+++ b/data/abi.ini
@@ -0,0 +1,14 @@
+[c]
+package=org.tizen.data-provider-slave
+
+[cpp]
+package=org.tizen.data-provider-slave
+
+[html]
+package=livebox.web-provider
+
+[osp]
+package=gi2qxenosh.osp-livebox-service
+
+[app]
+package=/APPID/
diff --git a/data/baltic.conf.ini b/data/baltic.conf.ini
new file mode 100644
index 0000000..d823052
--- /dev/null
+++ b/data/baltic.conf.ini
@@ -0,0 +1,30 @@
+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=5242880
+replace_tag=/APPID/
+slave_ttl=30.0
+slave_activate_time=30.0
+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=/opt/usr/share/live_magazine/log
+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
diff --git a/data/data-provider-master b/data/data-provider-master
new file mode 100755
index 0000000..9e2132a
--- /dev/null
+++ b/data/data-provider-master
@@ -0,0 +1,91 @@
+#!/bin/sh
+#
+# 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.
+#
+
+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
+ 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 ()
+{
+ 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..c4859e6
--- /dev/null
+++ b/data/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]
+Environment=BUFMGR_LOCK_TYPE="once"
+Environment=BUFMGR_MAP_CACHE="true"
+Type=simple
+ExecStart=/usr/bin/data-provider-master
+RestartSec=1
+
+[Install]
+WantedBy=tizen-middleware.target
diff --git a/data/private.conf.ini b/data/private.conf.ini
new file mode 100644
index 0000000..c5285fe
--- /dev/null
+++ b/data/private.conf.ini
@@ -0,0 +1,30 @@
+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=5242880
+replace_tag=/APPID/
+slave_ttl=30.0
+slave_activate_time=30.0
+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=/opt/usr/share/live_magazine/log
+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
diff --git a/data/resolution.ini b/data/resolution.ini
new file mode 100644
index 0000000..cf4275f
--- /dev/null
+++ b/data/resolution.ini
@@ -0,0 +1,10 @@
+1x1=175x175
+2x1=354x175
+2x2=354x354
+4x1=712x175
+4x2=712x354
+4x3=712x533
+4x4=712x712
+21x21=207x207
+23x21=645x207
+23x23=645x645
diff --git a/include/abi.h b/include/abi.h
new file mode 100644
index 0000000..ea70f7f
--- /dev/null
+++ b/include/abi.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+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 int abi_del_all(void);
+extern const char *abi_find_by_pkgname(const char *pkgname);
+
+/* End of a file */
diff --git a/include/buffer_handler.h b/include/buffer_handler.h
new file mode 100644
index 0000000..84be680
--- /dev/null
+++ b/include/buffer_handler.h
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+struct buffer_info;
+struct inst_info;
+
+enum buffer_type { /*!< Must have to be sync with libprovider, liblivebox-viewer */
+ 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
+ * \return int
+ */
+extern int buffer_handler_fini(void);
+
+extern void *buffer_handler_pixmap_ref(struct buffer_info *info);
+
+extern int buffer_handler_pixmap_unref(void *buffer_ptr);
+
+extern void *buffer_handler_pixmap_find(int pixmap);
+
+extern void *buffer_handler_pixmap_buffer(struct buffer_info *info);
+
+extern struct inst_info *buffer_handler_instance(struct buffer_info *info);
+
+/* End of a file */
diff --git a/include/client_life.h b/include/client_life.h
new file mode 100644
index 0000000..8a7ceb7
--- /dev/null
+++ b/include/client_life.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+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 int 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);
+
+extern const int const client_is_activated(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 int 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..afc8e4d
--- /dev/null
+++ b/include/client_rpc.h
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/*!
+ */
+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..98a479a
--- /dev/null
+++ b/include/conf.h
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+
+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;
+ } 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;
+
+ 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;
+ } 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;
+
+ double scale_width_factor;
+ double scale_height_factor;
+};
+
+extern struct conf g_conf;
+
+extern int conf_loader(void);
+
+#define BASE_W g_conf.base_width
+#define BASE_H g_conf.base_height
+
+#define CR 13
+#define LF 10
+
+#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 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 REPLACE_TAG_APPID g_conf.replace_tag
+#define SLAVE_TTL g_conf.slave_ttl
+#define SLAVE_ACTIVATE_TIME g_conf.slave_activate_time
+
+#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 SLAVE_MAX_LOAD g_conf.slave_max_load
+#define DEFAULT_PING_TIME g_conf.ping_time
+#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
+
+#define USE_XMONITOR g_conf.use_xmonitor
+
+#define HAPI __attribute__((visibility("hidden")))
+
+/* End of a file */
diff --git a/include/critical_log.h b/include/critical_log.h
new file mode 100644
index 0000000..070ac47
--- /dev/null
+++ b/include/critical_log.h
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+extern int critical_log(const char *func, int line, const char *fmt, ...);
+extern int critical_log_init(const char *tag);
+extern int 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..779250b
--- /dev/null
+++ b/include/dead_monitor.h
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+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..b7b7043
--- /dev/null
+++ b/include/debug.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#if !defined(FLOG)
+#define DbgPrint(format, arg...) LOGD("[%s/%s:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg)
+#define ErrPrint(format, arg...) LOGE("[%s/%s:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg)
+#else
+extern FILE *__file_log_fp;
+#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [%s/%s:%d] " format, 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)
+#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"
+
+/* End of a file */
diff --git a/include/fault_manager.h b/include/fault_manager.h
new file mode 100644
index 0000000..53de351
--- /dev/null
+++ b/include/fault_manager.h
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+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/fb.h b/include/fb.h
new file mode 100644
index 0000000..3a61505
--- /dev/null
+++ b/include/fb.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+struct fb_info;
+struct inst_info;
+
+extern int fb_init(void);
+extern int fb_fini(void);
+extern struct fb_info *fb_create(struct inst_info *inst, int w, int h, enum buffer_type type);
+extern int fb_destroy(struct fb_info *info);
+extern Ecore_Evas * const fb_canvas(struct fb_info *info);
+extern const char *fb_id(struct fb_info *info);
+extern int fb_get_size(struct fb_info *info, int *w, int *h);
+extern void fb_sync(struct fb_info *info);
+extern int fb_create_buffer(struct fb_info *info);
+extern int fb_destroy_buffer(struct fb_info *info);
+extern int fb_resize(struct fb_info *info, int w, int h);
+
+/*!
+ * \note Only for the pixmap
+ */
+extern void *fb_pixmap_render_pre(struct fb_info *info);
+extern int fb_pixmap_render_post(struct fb_info *info);
+
+/* End of a file */
diff --git a/include/group.h b/include/group.h
new file mode 100644
index 0000000..a61a58b
--- /dev/null
+++ b/include/group.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+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..30a4aef
--- /dev/null
+++ b/include/instance.h
@@ -0,0 +1,216 @@
+/*
+ * 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.
+ */
+
+/*!
+ * \note
+ * An instance has three states.
+ * ACTIVATED, DEACTIVATED, DESTROYED
+ *
+ * When the master is launched and someone requiers 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_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);
+
+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);
+
+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, int w, int h, double priority, const char *content, const char *title);
+extern void instance_set_pd_info(struct inst_info *inst, int w, int h);
+
+extern void instance_pd_updated(const char *pkgname, const char *id, const char *descfile);
+extern void instance_lb_updated(const char *pkgname, const char *id);
+extern void instance_lb_updated_by_instance(struct inst_info *inst);
+extern void instance_pd_updated_by_instance(struct inst_info *inst, const char *descfile);
+
+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_set_pinup(struct inst_info *inst, int pinup);
+extern int instance_resize(struct inst_info *inst, int w, int h);
+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);
+
+/*!
+ * \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);
+extern void instance_send_resized_event(struct inst_info *inst, int is_pd, int w, int h, int status);
+
+extern int instance_create_lb_buffer(struct inst_info *inst);
+extern int instance_create_pd_buffer(struct inst_info *inst);
+
+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);
+
+extern int instance_freeze_updator(struct inst_info *inst);
+extern int instance_thaw_updator(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 void instance_init(void);
+extern void instance_fini(void);
+
+/* End of a file */
diff --git a/include/io.h b/include/io.h
new file mode 100644
index 0000000..3bae7b7
--- /dev/null
+++ b/include/io.h
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+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 *lb_pkgname, int prime, void *data), void *data);
+extern int io_crawling_liveboxes(int (*cb)(const char *pkgname, int prime, void *data), void *data);
+extern int io_is_exists(const char *pkgname); /* Manifest Package Name */
+
+/* End of a file */
diff --git a/include/liveinfo.h b/include/liveinfo.h
new file mode 100644
index 0000000..592a8ee
--- /dev/null
+++ b/include/liveinfo.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+struct liveinfo;
+
+extern int liveinfo_init(void);
+extern int liveinfo_fini(void);
+extern struct liveinfo *liveinfo_create(pid_t pid, int handle);
+extern int 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 int liveinfo_close_fifo(struct liveinfo *info);
+
+/* End of a file */
diff --git a/include/main.h b/include/main.h
new file mode 100644
index 0000000..62077ae
--- /dev/null
+++ b/include/main.h
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+
diff --git a/include/package.h b/include/package.h
new file mode 100644
index 0000000..5112d8b
--- /dev/null
+++ b/include/package.h
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+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 *pkgname);
+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);
+
+/*!
+ * \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);
+
+/* End of a file */
diff --git a/include/parser.h b/include/parser.h
new file mode 100644
index 0000000..3f7e50e
--- /dev/null
+++ b/include/parser.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+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..c5c0d82
--- /dev/null
+++ b/include/pkgmgr.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+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..17ed04d
--- /dev/null
+++ b/include/rpc_to_slave.h
@@ -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.
+ */
+
+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..7ca8a4d
--- /dev/null
+++ b/include/script_handler.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+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 struct fb_info *script_handler_fb(struct script_info *info);
+extern void *script_handler_evas(struct script_info *info);
+extern int script_handler_parse_desc(const char *pkgname, const char *filename, 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_init(void);
+extern int script_fini(void);
+
+extern int script_signal_emit(Evas *e, const char *part, const char *signal, double sx, double sy, double ex, double ey);
+extern int script_handler_update_pointer(struct script_info *inst, double x, double y, int down);
+extern int script_handler_resize(struct script_info *info, int w, int h);
+
+/* End of a file */
diff --git a/include/server.h b/include/server.h
new file mode 100644
index 0000000..c6ad93c
--- /dev/null
+++ b/include/server.h
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+extern int server_init(void);
+extern int server_fini(void);
+
+/* End of a file */
diff --git a/include/setting.h b/include/setting.h
new file mode 100644
index 0000000..fbc9b95
--- /dev/null
+++ b/include/setting.h
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+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/slave_life.h b/include/slave_life.h
new file mode 100644
index 0000000..f5ac637
--- /dev/null
+++ b/include/slave_life.h
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+
+/*!
+ * 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
+ * SLAVE_ACTIVATED = { SLAVE_PAUSED, SLAVE_RESUMED }
+ */
+ SLAVE_PAUSED,
+ SLAVE_RESUMED,
+
+ SLAVE_ERROR = 0xFF, /* Explicitly define the size of this enum type */
+};
+
+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);
+
+/*!
+ * \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) __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);
+
+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);
+
+/* End of a file */
diff --git a/include/slave_rpc.h b/include/slave_rpc.h
new file mode 100644
index 0000000..e1fbd3b
--- /dev/null
+++ b/include/slave_rpc.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+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);
+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_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..e840ef0
--- /dev/null
+++ b/include/util.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+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 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 char *util_get_file_kept_in_safe(const char *id);
+extern double util_time_delay_for_compensation(double period);
+
+#define SCHEMA_FILE "file://"
+#define SCHEMA_PIXMAP "pixmap://"
+#define SCHEMA_SHM "shm://"
+
+/* End of a file */
diff --git a/include/xmonitor.h b/include/xmonitor.h
new file mode 100644
index 0000000..1ee8eab
--- /dev/null
+++ b/include/xmonitor.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+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.spec b/packaging/data-provider-master.spec
new file mode 100644
index 0000000..12727be
--- /dev/null
+++ b/packaging/data-provider-master.spec
@@ -0,0 +1,104 @@
+Name: data-provider-master
+Summary: Master service provider for liveboxes.
+Version: 0.17.2
+Release: 1
+Group: framework/livebox
+License: Flora License
+Source0: %{name}-%{version}.tar.gz
+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(bundle)
+BuildRequires: pkgconfig(ecore-x)
+BuildRequires: pkgconfig(ecore)
+BuildRequires: pkgconfig(evas)
+BuildRequires: pkgconfig(ecore-evas)
+BuildRequires: pkgconfig(com-core)
+BuildRequires: pkgconfig(heynoti)
+BuildRequires: pkgconfig(libxml-2.0)
+BuildRequires: pkgconfig(x11)
+BuildRequires: pkgconfig(libdri2)
+BuildRequires: pkgconfig(libdrm)
+BuildRequires: pkgconfig(libtbm)
+BuildRequires: pkgconfig(xfixes)
+BuildRequires: pkgconfig(dri2proto)
+BuildRequires: pkgconfig(xext)
+BuildRequires: pkgconfig(xdamage)
+BuildRequires: pkgconfig(pkgmgr)
+BuildRequires: pkgconfig(livebox-service)
+
+%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
+
+%build
+cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DPRODUCT=private
+CFLAGS="${CFLAGS} -Wall -Winline -Werror" LDFLAGS="${LDFLAGS}" make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+mkdir -p %{buildroot}/%{_datarootdir}/license
+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/dbspace
+mkdir -p %{buildroot}/%{_sysconfdir}/rc.d/rc3.d
+mkdir -p %{buildroot}/%{_libdir}/systemd/user/tizen-middleware.target.wants
+touch %{buildroot}/opt/dbspace/.livebox.db
+touch %{buildroot}/opt/dbspace/.livebox.db-journal
+ln -sf %{_sysconfdir}/rc.d/init.d/data-provider-master %{buildroot}/%{_sysconfdir}/rc.d/rc3.d/S99data-provider-master
+ln -sf %{_libdir}/systemd/user/data-provider-master.service %{buildroot}/%{_libdir}/systemd/user/tizen-middleware.target.wants/data-provider-master.service
+
+%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
+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
+echo "Successfully installed. Please start a daemon again manually"
+echo "%{_sysconfdir}/init.d/data-provider-master start"
+
+%files -n data-provider-master
+%manifest data-provider-master.manifest
+%defattr(-,root,root,-)
+%{_sysconfdir}/rc.d/init.d/data-provider-master
+%{_sysconfdir}/rc.d/rc3.d/S99data-provider-master
+%{_bindir}/data-provider-master
+%{_bindir}/liveinfo
+%{_prefix}/etc/package-manager/parserlib/*
+%{_datarootdir}/data-provider-master/*
+%{_libdir}/systemd/user/data-provider-master.service
+%{_libdir}/systemd/user/tizen-middleware.target.wants/data-provider-master.service
+%{_datarootdir}/license/*
+/opt/usr/share/live_magazine
+/opt/usr/share/live_magazine/log
+/opt/usr/share/live_magazine/reader
+/opt/usr/share/live_magazine/always
+/opt/dbspace/.livebox.db
+/opt/dbspace/.livebox.db-journal
+
+# 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..b4a5719
--- /dev/null
+++ b/pkgmgr_livebox/include/dlist.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define 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..3c258ec
--- /dev/null
+++ b/pkgmgr_livebox/livebox.xml
@@ -0,0 +1,76 @@
+<?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" touch_effect="true">
+ <size preview="ABSPATH">1x1</size>
+ <size preview="ABSPATH">2x1</size>
+ <size>2x2</size>
+ <size>4x1</size>
+ <size>4x2</size>
+ <size>4x3</size>
+ <size>4x4</size>
+
+ <!-- Easy home -->
+ <size>21x21</size>
+ <size preview="ABSPATH">23x21</size>
+ <size>23x23</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..56ff060
--- /dev/null
+++ b/pkgmgr_livebox/src/dlist.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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..653791a
--- /dev/null
+++ b/pkgmgr_livebox/src/service_register.c
@@ -0,0 +1,2537 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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...) LOGD("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg)
+#define ErrPrint(format, arg...) LOGE("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg)
+#endif
+/* End of a file */
+
+/*!
+ * \note
+ * DB Table schema
+ *
+ * pkgmap
+ * +-------+-------+---------+
+ * | appid | pkgid | prime |
+ * +-------+-------+---------+
+ * | - | - | |
+ * +-------+-------+---------+
+ * CREATE TABLE pkgmap ( pkgid TEXT PRIMARY KEY NOT NULL, appid TEXT, prime INTEGER )
+ *
+ *
+ * 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 | mouse_event | touch_effect |
+ * +-------+------+---------+-------------+---------+---------+-----------+-------+-------------+--------------+
+ * | - | - | - | - | - | - | - | - | - } - |
+ * +-------+------+---------+-------------+---------+---------+-----------+-------+-------------+--------------+
+ * CREATE TABLE client ( pkgid TEXT PRIMARY KEY NOT NULL, icon TEXT, name TEXT, auto_launch TEXT, pd_size TEXT, content TEXT DEFAULT "default", nodisplay INTEGER, setup TEXT, mouse_event INTEGER, touch_effect INTEGER, 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 |
+ * +-------+-----------+---------+
+ * | - | - | - |
+ * +-------+-----------+---------+
+ * CREATE TABLE box_size ( pkgid TEXT NOT NULL, size_type INTEGER, preview TEXT, 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;
+
+ int pinup; /* Is this support the pinup feature? */
+ int primary; /* Is this primary livebox? */
+ int nodisplay;
+ int mouse_event; /* Mouse event processing option for livebox */
+ int touch_effect; /* Touch effect of a livebox */
+
+ enum lb_type lb_type;
+ xmlChar *lb_src;
+ xmlChar *lb_group;
+ int size_list; /* 1x1, 2x1, 2x2, 4x1, 4x2, 4x3, 4x4 */
+
+ xmlChar *preview[10];
+
+ 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 inline int db_create_pkgmap(void)
+{
+ char *err;
+ static const char *ddl;
+
+ ddl = "CREATE TABLE pkgmap ( pkgid TEXT PRIMARY KEY NOT NULL, appid TEXT, prime INTEGER )";
+ 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, int primary)
+{
+ int ret;
+ static const char *dml;
+ sqlite3_stmt *stmt;
+
+ dml = "INSERT INTO pkgmap ( appid, pkgid, prime ) 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_int(stmt, 3, primary);
+ 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 inline 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 (!box_src)
+ box_src = "";
+
+ if (!box_group)
+ box_group = "";
+
+ if (!pd_src)
+ pd_src = "";
+
+ if (!pd_group)
+ pd_group = "";
+
+ if (!libexec)
+ libexec = "";
+
+ 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) {
+ DbgPrint("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) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+
+ ret = sqlite3_bind_int(stmt, 2, livebox->network);
+ if (ret != SQLITE_OK) {
+ DbgPrint("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) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+ ret = sqlite3_bind_int(stmt, 4, livebox->secured);
+ if (ret != SQLITE_OK) {
+ DbgPrint("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) {
+ DbgPrint("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) {
+ DbgPrint("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) {
+ DbgPrint("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) {
+ DbgPrint("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) {
+ DbgPrint("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) {
+ DbgPrint("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) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 12, atoi(timeout));
+ if (ret != SQLITE_OK) {
+ DbgPrint("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) {
+ DbgPrint("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) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 15, livebox->pinup);
+ 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_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 DEFAULT 'default', nodisplay INTEGER, setup TEXT, mouse_event INTEGER, touch_effect 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_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, mouse_event, touch_effect ) 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, (char *)livebox->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, 2, (char *)livebox->icon, -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, (char *)livebox->name, -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, 4, (char *)livebox->auto_launch, -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, 5, (char *)livebox->pd_size, -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, 6, livebox->content ? (char *)livebox->content : "default", -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, 7, livebox->nodisplay);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 8, livebox->setup ? (char *)livebox->setup : "", -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, 9, livebox->mouse_event);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 10, livebox->touch_effect);
+ 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_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) {
+ 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 = sqlite3_bind_text(stmt, 2, lang, -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, name, -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, 4, icon, -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_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) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, cluster, -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, category, -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, 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_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) {
+ 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_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_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) {
+ 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 = sqlite3_bind_int(stmt, 2, option_id);
+ if (ret != SQLITE_OK) {
+ DbgPrint("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) {
+ DbgPrint("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) {
+ 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_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, " \
+ "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_box_size(const char *pkgid, int size_type, const char *preview)
+{
+ 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 ) 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, pkgid, -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, 2, size_type);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 3, preview ? preview : "", -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_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 inline int db_init(void)
+{
+ int ret;
+ struct stat stat;
+
+ ret = db_util_open(s_info.dbfile, &s_info.handle, DB_UTIL_REGISTER_HOOK_METHOD);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Failed to open a DB\n");
+ return -EIO;
+ }
+
+ if (lstat(s_info.dbfile, &stat) < 0) {
+ ErrPrint("%s\n", strerror(errno));
+ db_util_close(s_info.handle);
+ s_info.handle = NULL;
+ return -EIO;
+ }
+
+ if (!S_ISREG(stat.st_mode)) {
+ ErrPrint("Invalid file\n");
+ db_util_close(s_info.handle);
+ s_info.handle = NULL;
+ return -EINVAL;
+ }
+
+ if (!stat.st_size)
+ db_create_table();
+
+ return 0;
+}
+
+static inline int db_fini(void)
+{
+ if (!s_info.handle)
+ return 0;
+
+ db_util_close(s_info.handle);
+ s_info.handle = NULL;
+
+ return 0;
+}
+
+static inline int validate_pkgid(const char *appid, const char *pkgid)
+{
+ /* Just return 1 Always */
+ return 1 || !strncmp(appid, pkgid, strlen(appid));
+}
+
+static inline 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->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]); /* 21x21 */
+ xmlFree(livebox->preview[8]); /* 23x21 */
+ xmlFree(livebox->preview[9]); /* 23x23 */
+
+ 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;
+ }
+
+ livebox->auto_launch = xmlStrdup(launch);
+ if (!livebox->auto_launch) {
+ ErrPrint("Failed to duplicate string: %s\n", (char *)launch);
+ return;
+ }
+}
+
+static inline void update_setup(struct livebox *livebox, xmlNodePtr node)
+{
+ xmlChar *setup;
+ setup = xmlNodeGetContent(node);
+ if (!setup) {
+ DbgPrint("Has no setup\n");
+ return;
+ }
+
+ 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;
+ }
+
+ livebox->content = xmlStrdup(content);
+ if (!livebox->content) {
+ ErrPrint("Failed to duplicate string: %s\n", (char *)content);
+ return;
+ }
+}
+
+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->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->mouse_event = 0;
+ } else {
+ livebox->mouse_event = !xmlStrcasecmp(mouse_event, (const xmlChar *)"true");
+ xmlFree(mouse_event);
+ }
+ }
+
+ if (!xmlHasProp(node, (const xmlChar *)"touch_effect")) {
+ livebox->touch_effect = 1;
+ } else {
+ xmlChar *touch_effect;
+ touch_effect = xmlGetProp(node, (const xmlChar *)"touch_effect");
+ if (!touch_effect) {
+ ErrPrint("touch_effect is NIL\n");
+ livebox->touch_effect = 1;
+ } else {
+ livebox->touch_effect = !xmlStrcasecmp(touch_effect, (const xmlChar *)"true");
+ xmlFree(touch_effect);
+ }
+ }
+
+ 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;
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[7] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+ } else {
+ livebox->size_list |= LB_SIZE_TYPE_1x1;
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[0] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+ }
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"3x1")) {
+ if (is_easy) {
+ livebox->size_list |= LB_SIZE_TYPE_EASY_3x1;
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[8] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+ } 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;
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[9] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+ } else {
+ ErrPrint("Invalid size tag (%s)\n", size);
+ }
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"2x1")) {
+ livebox->size_list |= LB_SIZE_TYPE_2x1;
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[1] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"2x2")) {
+ livebox->size_list |= LB_SIZE_TYPE_2x2;
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[2] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"4x1")) {
+ livebox->size_list |= LB_SIZE_TYPE_4x1;
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[3] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"4x2")) {
+ livebox->size_list |= LB_SIZE_TYPE_4x2;
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[4] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"4x3")) {
+ livebox->size_list |= LB_SIZE_TYPE_4x3;
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[5] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"4x4")) {
+ livebox->size_list |= LB_SIZE_TYPE_4x4;
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[6] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"21x21")) {
+ livebox->size_list |= LB_SIZE_TYPE_EASY_1x1;
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[7] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"23x21")) {
+ livebox->size_list |= LB_SIZE_TYPE_EASY_3x1;
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[8] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"23x23")) {
+ livebox->size_list |= LB_SIZE_TYPE_EASY_3x3;
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[9] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+ } 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 inline 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, livebox->primary);
+ 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]);
+ 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]);
+ 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]);
+ 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]);
+ 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]);
+ 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]);
+ 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]);
+ 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[7]);
+ 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[8]);
+ 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[9]);
+ 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 inline 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;
+ }
+ }
+
+ return db_insert_livebox(livebox, appid);
+}
+
+int PKGMGR_PARSER_PLUGIN_INSTALL(xmlDocPtr docPtr, const char *appid)
+{
+ xmlNodePtr node;
+ int ret;
+
+ if (!s_info.handle) {
+ if (db_init() < 0) {
+ 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) {
+ DbgPrint("node->name: %s\n", node->name);
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"livebox")) {
+ ret = do_install(node, appid);
+ DbgPrint("Returns: %d\n", ret);
+ }
+ }
+
+ return 0;
+}
+
+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;
+}
+
+int PKGMGR_PARSER_PLUGIN_UPGRADE(xmlDocPtr docPtr, const char *appid)
+{
+ xmlNodePtr node;
+ int ret;
+
+ if (!s_info.handle) {
+ if (db_init() < 0) {
+ 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_uninstall(node, appid);
+ ret = do_install(node, appid);
+ DbgPrint("Returns: %d\n", ret);
+ }
+ }
+
+ return 0;
+}
+
+int PKGMGR_PARSER_PLUGIN_UNINSTALL(xmlDocPtr docPtr, const char *appid)
+{
+ xmlNodePtr node;
+ int ret;
+
+ if (!s_info.handle) {
+ if (db_init() < 0) {
+ 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_uninstall(node, appid);
+ DbgPrint("Returns: %d\n", ret);
+ }
+ }
+
+ 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..f7470aa
--- /dev/null
+++ b/res/edje/master.edc
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+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..62db6c9
--- /dev/null
+++ b/src/abi.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <Eina.h>
+#include <dlog.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 -ENOMEM;
+ }
+
+ item->abi = strdup(abi);
+ if (!item->abi) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item);
+ return -ENOMEM;
+ }
+
+ item->pkgname = strdup(pkgname);
+ if (!item->pkgname) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item->abi);
+ DbgFree(item);
+ return -ENOMEM;
+ }
+
+ s_abi.list = eina_list_append(s_abi.list, item);
+ return 0;
+}
+
+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 -ENOMEM;
+ }
+
+ 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 -ENOENT;
+}
+
+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 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+HAPI int abi_del_all(void)
+{
+ struct item *item;
+
+ EINA_LIST_FREE(s_abi.list, item) {
+ DbgFree(item->abi);
+ DbgFree(item->pkgname);
+ DbgFree(item);
+ }
+
+ return 0;
+}
+
+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/buffer_handler.c b/src/buffer_handler.c
new file mode 100644
index 0000000..59346cb
--- /dev/null
+++ b/src/buffer_handler.c
@@ -0,0 +1,1326 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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 "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"
+
+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;
+
+ enum buffer_type type;
+
+ int w;
+ int h;
+ int pixel_size;
+ int is_loaded;
+
+ struct inst_info *inst;
+};
+
+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,
+};
+
+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:
+ info->id = strdup(SCHEMA_SHM "-1");
+ if (!info->id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info);
+ return NULL;
+ }
+ break;
+ case BUFFER_TYPE_FILE:
+ 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");
+ if (!info->id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info);
+ return NULL;
+ }
+ break;
+ default:
+ ErrPrint("Invalid type\n");
+ DbgFree(info);
+ return NULL;
+ }
+
+ info->w = w;
+ info->h = h;
+ info->pixel_size = pixel_size;
+ info->type = type;
+ info->is_loaded = 0;
+ info->inst = inst;
+ info->buffer = NULL;
+
+ DbgPrint("%dx%d size buffer is created\n", w, h);
+ return info;
+}
+
+static inline struct buffer *create_pixmap(struct buffer_info *info)
+{
+ struct gem_data *gem;
+ struct buffer *buffer;
+ Display *disp;
+ Window parent;
+
+ 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;
+
+ DbgPrint("Canvas %dx%d - %d is created\n", info->w, info->h, info->pixel_size);
+
+ 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.
+ */
+ gem->pixmap = XCreatePixmap(disp, parent, info->w, info->h, 24 /* (info->pixel_size << 3) */);
+ if (gem->pixmap == (Pixmap)0) {
+ ErrPrint("Failed to create a pixmap\n");
+ DbgFree(buffer);
+ return NULL;
+ }
+
+ XSync(disp, False);
+
+ DbgPrint("Pixmap:0x%X is created\n", gem->pixmap);
+ 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 -EIO;
+ }
+
+ 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 -ENOMEM;
+ }
+
+ DbgPrint("DRI2(gem) is not supported - Fallback to the S/W Backend\n");
+ return 0;
+ }
+
+ DRI2CreateDrawable(disp, gem->pixmap);
+ DbgPrint("DRI2CreateDrawable is done\n");
+
+ 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 -EFAULT;
+ }
+ DbgPrint("dri2_buffer: %p, name: %p, %dx%d\n",
+ gem->dri2_buffer, gem->dri2_buffer->name, gem->w, gem->h);
+ DbgPrint("dri2_buffer->pitch : %d, buf_count: %d\n",
+ gem->dri2_buffer->pitch, gem->buf_count);
+
+ /*!
+ * \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 -EFAULT;
+ }
+
+ 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");
+ } else {
+ DbgPrint("Allocate compensate buffer %p(%dx%d %d)\n",
+ gem->compensate_data,
+ gem->w, gem->h, gem->depth);
+ }
+ }
+
+ return 0;
+}
+
+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) {
+ DbgPrint("GEM is not supported - Use the fake gem buffer\n");
+ } else {
+ if (!gem->pixmap_bo) {
+ DbgPrint("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) {
+ DbgPrint("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) {
+ DbgPrint("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 -EIO;
+
+ DbgPrint("Free pixmap 0x%X\n", gem->pixmap);
+ XFreePixmap(disp, gem->pixmap);
+ }
+
+ buffer->state = DESTROYED;
+ DbgFree(buffer);
+ return 0;
+}
+
+static inline int destroy_gem(struct buffer *buffer)
+{
+ struct gem_data *gem;
+
+ if (!buffer)
+ return -EINVAL;
+
+ /*!
+ * Forcely release the acquire_buffer.
+ */
+ gem = (struct gem_data *)buffer->data;
+ if (!gem)
+ return -EFAULT;
+
+ if (s_info.fd >= 0) {
+ if (gem->compensate_data) {
+ DbgPrint("Release compensate buffer %p\n", gem->compensate_data);
+ free(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;
+
+ DbgPrint("DRI2DestroyDrawable\n");
+ DRI2DestroyDrawable(ecore_x_display_get(), gem->pixmap);
+ }
+ } else if (gem->data) {
+ DbgPrint("Release fake gem buffer\n");
+ DbgFree(gem->data);
+ gem->data = NULL;
+ }
+
+ return 0;
+}
+
+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 -ENOMEM;
+ }
+
+ 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 -EINVAL;
+ }
+
+ buffer = calloc(1, size);
+ if (!buffer) {
+ ErrPrint("Failed to allocate buffer\n");
+ DbgFree(new_id);
+ return -ENOMEM;
+ }
+
+ 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 0;
+}
+
+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 -EINVAL;
+ }
+
+ id = shmget(IPC_PRIVATE, size + sizeof(*buffer), IPC_CREAT | 0666);
+ if (id < 0) {
+ ErrPrint("shmget: %s\n", strerror(errno));
+ return -EFAULT;
+ }
+
+ 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 -EFAULT;
+ }
+
+ buffer->type = BUFFER_TYPE_SHM;
+ buffer->refcnt = id;
+ buffer->state = CREATED; /*!< Needless */
+ buffer->info = NULL; /*!< This has not to be used, every process will see this. So, don't try to save anything on here */
+
+ 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 -ENOMEM;
+ }
+
+ snprintf(new_id, len, SCHEMA_SHM "%d", id);
+
+ DbgFree(info->id);
+ info->id = new_id;
+ info->buffer = buffer;
+ info->is_loaded = 1;
+ return 0;
+}
+
+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 -EFAULT;
+ }
+
+ len = strlen(SCHEMA_PIXMAP) + 30; /* strlen("pixmap://") + 30 */
+ new_id = malloc(len);
+ if (!new_id) {
+ info->is_loaded = 0;
+ ErrPrint("Heap: %s\n", strerror(errno));
+ buffer_handler_pixmap_unref(buffer);
+ return -ENOMEM;
+ }
+
+ DbgPrint("Releaseo old id (%s)\n", info->id);
+ DbgFree(info->id);
+ info->id = new_id;
+
+ gem = (struct gem_data *)buffer->data;
+ DbgPrint("gem pointer: %p\n", gem);
+
+ snprintf(info->id, len, SCHEMA_PIXMAP "%d", (int)gem->pixmap);
+ DbgPrint("info->id: %s\n", info->id);
+
+ return 0;
+}
+
+HAPI int buffer_handler_load(struct buffer_info *info)
+{
+ int ret;
+
+ if (!info) {
+ DbgPrint("buffer handler is nil\n");
+ return -EINVAL;
+ }
+
+ if (info->is_loaded) {
+ DbgPrint("Buffer is already loaded\n");
+ return 0;
+ }
+
+ switch (info->type) {
+ case BUFFER_TYPE_FILE:
+ ret = load_file_buffer(info);
+ break;
+ case BUFFER_TYPE_SHM:
+ ret = load_shm_buffer(info);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ ret = load_pixmap_buffer(info);
+ break;
+ default:
+ ErrPrint("Invalid buffer\n");
+ ret = -EINVAL;
+ 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 -ENOMEM;
+ }
+
+ 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 0;
+}
+
+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 -ENOMEM;
+ }
+
+ if (sscanf(info->id, SCHEMA_SHM "%d", &id) != 1) {
+ ErrPrint("%s Invalid ID\n", info->id);
+ DbgFree(new_id);
+ return -EINVAL;
+ }
+
+ if (id < 0) {
+ ErrPrint("(%s) Invalid id: %d\n", info->id, id);
+ DbgFree(new_id);
+ return -EINVAL;
+ }
+
+ 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 0;
+}
+
+static inline int unload_pixmap_buffer(struct buffer_info *info)
+{
+ int id;
+ char *new_id;
+
+ new_id = strdup(SCHEMA_PIXMAP "0");
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ if (sscanf(info->id, SCHEMA_PIXMAP "%d", &id) != 1) {
+ ErrPrint("Invalid ID (%s)\n", info->id);
+ DbgFree(new_id);
+ return -EINVAL;
+ }
+
+ if (id == 0) {
+ ErrPrint("(%s) Invalid id: %d\n", info->id, id);
+ DbgFree(new_id);
+ return -EINVAL;
+ }
+
+ /*!
+ * 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 0;
+}
+
+HAPI int buffer_handler_unload(struct buffer_info *info)
+{
+ int ret;
+
+ if (!info) {
+ DbgPrint("buffer handler is nil\n");
+ return -EINVAL;
+ }
+
+ if (!info->is_loaded) {
+ ErrPrint("Buffer is not loaded\n");
+ return -EINVAL;
+ }
+
+ switch (info->type) {
+ case BUFFER_TYPE_FILE:
+ ret = unload_file_buffer(info);
+ break;
+ case BUFFER_TYPE_SHM:
+ ret = unload_shm_buffer(info);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ ret = unload_pixmap_buffer(info);
+ break;
+ default:
+ ErrPrint("Invalid buffer\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret == 0)
+ info->is_loaded = 0;
+
+ return ret;
+}
+
+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 0;
+ }
+
+ 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 0;
+}
+
+HAPI const char *buffer_handler_id(const struct buffer_info *info)
+{
+ return info ? info->id : "";
+}
+
+HAPI enum buffer_type buffer_handler_type(const struct buffer_info *info)
+{
+ return info ? info->type : BUFFER_TYPE_ERROR;
+}
+
+HAPI 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;
+
+ /*!
+ */
+ canvas = buffer_handler_pixmap_acquire_buffer(info);
+ ret = buffer_handler_pixmap_release_buffer(canvas);
+ DbgPrint("Canvas %p(%d) (released but still in use)\n", canvas, ret);
+ return canvas;
+ }
+
+ return buffer->data;
+}
+
+HAPI 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;
+}
+
+HAPI 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);
+}
+
+HAPI 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)
+ */
+HAPI 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) {
+ DbgPrint("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) {
+ DbgPrint("Doesn't need to create gem for LB\n");
+ need_gem = 0;
+ }
+ } else if (instance_pd_buffer(info->inst) == info) {
+ pkg = instance_package(info->inst);
+ if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ DbgPrint("Doesn't need to create gem for PD\n");
+ 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"
+ */
+HAPI 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;
+}
+
+HAPI 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 -EINVAL;
+
+ 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 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/*!
+ * \note
+ *
+ * \return Return NULL if the buffer is in still uses.
+ * Return buffer_ptr if it needs to destroy
+ */
+HAPI int buffer_handler_pixmap_unref(void *buffer_ptr)
+{
+ struct buffer *buffer = buffer_ptr;
+ struct buffer_info *info;
+
+ buffer->refcnt--;
+ if (buffer->refcnt > 0)
+ return 0; /* Return NULL means, gem buffer still in use */
+
+ s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
+
+ if (destroy_gem(buffer) < 0)
+ ErrPrint("Failed to destroy gem buffer\n");
+
+ if (destroy_pixmap(buffer) < 0)
+ ErrPrint("Failed to destroy pixmap\n");
+
+ info = buffer->info;
+ if (info && info->buffer == buffer)
+ info->buffer = NULL;
+
+ return 0;
+}
+
+HAPI int buffer_handler_is_loaded(const struct buffer_info *info)
+{
+ return info ? info->is_loaded : 0;
+}
+
+HAPI void buffer_handler_update_size(struct buffer_info *info, int w, int h)
+{
+ if (!info)
+ return;
+
+ info->w = w;
+ info->h = h;
+}
+
+HAPI int buffer_handler_resize(struct buffer_info *info, int w, int h)
+{
+ int ret;
+
+ if (!info) {
+ ErrPrint("Invalid handler\n");
+ return -EINVAL;
+ }
+
+ if (info->w == w && info->h == h) {
+ DbgPrint("No changes\n");
+ return 0;
+ }
+
+ buffer_handler_update_size(info, w, h);
+
+ if (!info->is_loaded) {
+ DbgPrint("Not yet loaded, just update the size [%dx%d]\n", w, h);
+ return 0;
+ }
+
+ 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 0;
+}
+
+HAPI int buffer_handler_get_size(struct buffer_info *info, int *w, int *h)
+{
+ if (!info)
+ return -EINVAL;
+
+ if (w)
+ *w = info->w;
+ if (h)
+ *h = info->h;
+
+ return 0;
+}
+
+HAPI 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 -EINVAL;
+ }
+
+ if (buffer->type != BUFFER_TYPE_PIXMAP) {
+ DbgPrint("Invalid buffer\n");
+ return 0;
+ }
+
+ disp = ecore_x_display_get();
+ if (!disp) {
+ ErrPrint("Failed to get a display\n");
+ return -EFAULT;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+ if (gem->w == 0 || gem->h == 0) {
+ DbgPrint("Nothing can be sync\n");
+ return 0;
+ }
+
+ 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 -EFAULT;
+ }
+
+ 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 -EFAULT;
+ }
+
+ screen = DefaultScreenOfDisplay(disp);
+ visual = DefaultVisualOfScreen(screen);
+ /*!
+ * \NOTE
+ * XCreatePixmap can only uses 24 bits depth only.
+ */
+ xim = XShmCreateImage(disp, visual, 24 /* (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 -EFAULT;
+ }
+
+ 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 -EFAULT;
+ }
+
+ 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 0;
+}
+
+HAPI 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) {
+ 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());
+ } 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;
+ if (write(fd, info->buffer, size) != size)
+ ErrPrint("Write is not completed: %s\n", strerror(errno));
+
+ close(fd);
+ } 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)) {
+ DbgPrint("DRI2 is not supported\n");
+ return 0;
+ }
+
+ if (!DRI2QueryVersion(ecore_x_display_get(), &dri2Major, &dri2Minor)) {
+ DbgPrint("DRI2 is not supported\n");
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return 0;
+ }
+
+ if (!DRI2Connect(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), &driverName, &deviceName)) {
+ DbgPrint("DRI2 is not supported\n");
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return 0;
+ }
+
+ DbgPrint("Open: %s (driver: %s)", deviceName, driverName);
+
+ 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 0;
+ }
+
+ s_info.fd = open(deviceName, O_RDWR);
+ DbgFree(deviceName);
+ DbgFree(driverName);
+ if (s_info.fd < 0) {
+ DbgPrint("Failed to open a drm device: (%s)\n", strerror(errno));
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return 0;
+ }
+
+ 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)) {
+ DbgPrint("Failed to do authenticate for DRI2\n");
+ close(s_info.fd);
+ s_info.fd = -1;
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return 0;
+ }
+
+ s_info.slp_bufmgr = tbm_bufmgr_init(s_info.fd);
+ if (!s_info.slp_bufmgr) {
+ DbgPrint("Failed to init bufmgr\n");
+ close(s_info.fd);
+ s_info.fd = -1;
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return 0;
+ }
+
+ return 0;
+}
+
+HAPI int buffer_handler_fini(void)
+{
+ if (s_info.fd >= 0) {
+ close(s_info.fd);
+ s_info.fd = -1;
+ }
+
+ if (s_info.slp_bufmgr) {
+ tbm_bufmgr_deinit(s_info.slp_bufmgr);
+ s_info.slp_bufmgr = NULL;
+ }
+
+ return 0;
+}
+
+/* End of a file */
diff --git a/src/client_life.c b/src/client_life.c
new file mode 100644
index 0000000..f795feb
--- /dev/null
+++ b/src/client_life.c
@@ -0,0 +1,791 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+
+#include <dlog.h>
+#include <packet.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;
+
+ Eina_List *create_event_list;
+ Eina_List *destroy_event_list;
+} s_info = {
+ .client_list = NULL,
+ .nr_of_paused_clients = 0,
+ .create_event_list = NULL,
+ .destroy_event_list = NULL,
+};
+
+struct subscribe_item {
+ char *cluster;
+ char *category;
+};
+
+struct global_event_handler {
+ void *cbdata;
+ int (*cb)(struct client_node *client, void *data);
+};
+
+struct data_item {
+ char *tag;
+ void *data;
+};
+
+struct event_item {
+ void *data;
+ int (*cb)(struct client_node *, void *);
+};
+
+struct client_node {
+ pid_t pid;
+ int refcnt;
+
+ int paused;
+
+ 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_handler *item;
+
+ EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, item) {
+ if (!item->cb) {
+ ErrPrint("Callback function is not valid\n");
+ continue;
+ }
+
+ if (item->cb(client, item->cbdata) < 0) {
+ if (eina_list_data_find(s_info.destroy_event_list, item)) {
+ s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, item);
+ DbgFree(item);
+ }
+ }
+ }
+}
+
+static inline void invoke_global_created_cb(struct client_node *client)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct global_event_handler *item;
+
+ EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, item) {
+ if (!item->cb) {
+ ErrPrint("Callback function is not valid\n");
+ continue;
+ }
+
+ if (item->cb(client, item->cbdata) < 0) {
+ if (eina_list_data_find(s_info.create_event_list, item)) {
+ s_info.create_event_list = eina_list_remove(s_info.create_event_list, item);
+ DbgFree(item);
+ }
+ }
+ }
+}
+
+static inline void invoke_deactivated_cb(struct client_node *client)
+{
+ struct event_item *item;
+ Eina_List *l;
+ Eina_List *n;
+ int ret;
+
+ client_ref(client); /*!< Prevent from client deletion in the callbacks */
+ EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
+ ret = item->cb(client, item->data);
+ if (ret < 0) {
+ if (eina_list_data_find(client->event_deactivate_list, item)) {
+ client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
+ DbgFree(item);
+ }
+ }
+ }
+ client_unref(client);
+}
+
+static inline void invoke_activated_cb(struct client_node *client)
+{
+ struct event_item *item;
+ Eina_List *l;
+ Eina_List *n;
+ int ret;
+
+ client_ref(client); /*!< Prevent from client deletion in the callbacks */
+ EINA_LIST_FOREACH_SAFE(client->event_activate_list, l, n, item) {
+ ret = item->cb(client, item->data);
+ if (ret < 0) {
+ if (eina_list_data_find(client->event_activate_list, item)) {
+ client->event_activate_list = eina_list_remove(client->event_activate_list, item);
+ DbgFree(item);
+ }
+ }
+ }
+}
+
+static inline void destroy_client_data(struct client_node *client)
+{
+ struct event_item *event;
+ struct data_item *data;
+ struct subscribe_item *item;
+
+ DbgPrint("Client %p is destroyed\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)
+{
+ 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));
+ 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_pid(pid);
+ if (client) {
+ ErrPrint("Client %d is already exists\n", pid);
+ 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 {
+ /*!
+ * \note
+ * To save the time to send reply packet to the client.
+ */
+ if (ecore_timer_add(DELAY_TIME, created_cb, client) == NULL) {
+ ErrPrint("Failed to add a timer for client created event\n");
+ client = client_unref(client);
+ return NULL;
+ }
+ }
+
+ 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 int client_deactivated_by_fault(struct client_node *client)
+{
+ if (!client || client->faulted)
+ return 0;
+
+ 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);
+ (void)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 0;
+}
+
+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 -EINVAL;
+ }
+
+ item = calloc(1, sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ item->cb = cb;
+ item->data = data;
+
+ /*!
+ * \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 -EINVAL;
+ }
+
+ return 0;
+}
+
+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 -EINVAL;
+ }
+
+ switch (event) {
+ case CLIENT_EVENT_DEACTIVATE:
+ EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
+ if (item->cb == cb && item->data == data) {
+ client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
+ DbgFree(item);
+ return 0;
+ }
+ }
+ break;
+
+ case CLIENT_EVENT_ACTIVATE:
+ EINA_LIST_FOREACH_SAFE(client->event_activate_list, l, n, item) {
+ if (item->cb == cb && item->data == data) {
+ client->event_activate_list = eina_list_remove(client->event_activate_list, item);
+ DbgFree(item);
+ return 0;
+ }
+ }
+ break;
+
+ default:
+ ErrPrint("Invalid event\n");
+ break;
+ }
+
+ return -ENOENT;
+}
+
+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 -ENOMEM;
+ }
+
+ item->tag = strdup(tag);
+ if (!item->tag) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item);
+ return -ENOMEM;
+ }
+
+ item->data = data;
+
+ client->data_list = eina_list_append(client->data_list, item);
+ return 0;
+}
+
+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 0;
+}
+
+HAPI int client_fini(void)
+{
+ struct global_event_handler *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);
+ }
+
+ return 0;
+}
+
+HAPI const int const client_is_activated(const struct client_node *client)
+{
+ return client ? (client->pid != (pid_t)-1) : 1;
+}
+
+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_handler *handler;
+
+ handler = malloc(sizeof(*handler));
+ if (!handler) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ handler->cbdata = data;
+ handler->cb = cb;
+
+ 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 -EINVAL;
+ }
+
+ return 0;
+}
+
+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_handler *handler;
+
+ switch (event_type) {
+ case CLIENT_GLOBAL_EVENT_CREATE:
+ EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, handler) {
+ if (handler->cb == cb && handler->cbdata == data) {
+ s_info.create_event_list = eina_list_remove(s_info.create_event_list, handler);
+ DbgFree(handler);
+ return 0;
+ }
+ }
+ break;
+ case CLIENT_GLOBAL_EVENT_DESTROY:
+ EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, handler) {
+ if (handler->cb == cb && handler->cbdata == data) {
+ s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, handler);
+ DbgFree(handler);
+ return 0;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return -ENOENT;
+}
+
+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 -ENOMEM;
+ }
+
+ item->cluster = strdup(cluster);
+ if (!item->cluster) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item);
+ return -ENOMEM;
+ }
+
+ item->category = strdup(category);
+ if (!item->category) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item->cluster);
+ DbgFree(item);
+ return -ENOMEM;
+ }
+
+ client->subscribe_list = eina_list_append(client->subscribe_list, item);
+ return 0;
+}
+
+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 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+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 -EINVAL;
+
+ 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 -ECANCELED;
+
+ 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) < 0) {
+ 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 0;
+}
+
+/* End of a file */
diff --git a/src/client_rpc.c b/src/client_rpc.c
new file mode 100644
index 0000000..8266ffe
--- /dev/null
+++ b/src/client_rpc.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+
+#include <dlog.h>
+#include <com-core_packet.h>
+#include <packet.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_activated(command->client)) {
+ ErrPrint("Client[%p] is not activated, destroy this command\n", command->client);
+ 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("Invalid command\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 -EINVAL;
+
+ if (client_is_faulted(client)) {
+ ErrPrint("Client[%p] is faulted\n", client);
+ packet_unref(packet);
+ return -EFAULT;
+ }
+
+ 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 -ENOMEM;
+ }
+
+ push_command(command);
+ packet_unref(packet);
+ return 0;
+}
+
+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 0;
+ }
+
+ 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 0;
+}
+
+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 -ENOMEM;
+ }
+
+ 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;
+
+ client_event_callback_add(client, CLIENT_EVENT_DEACTIVATE, deactivated_cb, NULL);
+ return 0;
+}
+
+HAPI int client_rpc_fini(struct client_node *client)
+{
+ struct client_rpc *rpc;
+
+ rpc = client_del_data(client, RPC_TAG);
+ if (!rpc)
+ return -EINVAL;
+
+ client_event_callback_del(client, CLIENT_EVENT_DEACTIVATE, deactivated_cb, NULL);
+ DbgFree(rpc);
+ return 0;
+}
+
+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 -EINVAL;
+ }
+
+ return rpc->handle;
+}
+
+/* End of a file */
diff --git a/src/conf.c b/src/conf.c
new file mode 100644
index 0000000..aab6a7a
--- /dev/null
+++ b/src/conf.c
@@ -0,0 +1,643 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Ecore_X.h>
+#include <ctype.h>
+
+#include <dlog.h>
+
+#include "conf.h"
+#include "util.h"
+#include "debug.h"
+
+HAPI struct conf g_conf = {
+ .width = 0,
+ .height = 0,
+
+ .base_width = 720,
+ .base_height = 1280,
+
+ .minimum_period = 1.0f,
+
+ .default_conf.script = "edje",
+ .default_conf.abi = "c",
+ .default_conf.pd_group = "disclosure",
+ .default_conf.period = -1.0f,
+
+ .launch_key.name = "name",
+ .launch_key.secured = "secured",
+ .launch_key.abi = "abi",
+
+ .default_packet_time = 0.0001f,
+
+ .empty_content = "",
+ .empty_title = "",
+
+ .default_content = "default",
+ .default_title = "",
+
+ .minimum_space = 5242880,
+
+ .replace_tag = "/APPID/",
+
+ .slave_ttl = 30.0f,
+ .slave_activate_time = 30.0f,
+
+ .max_log_line = 1000,
+ .max_log_file = 3,
+
+ .sqlite_flush_max = 1048576,
+
+ .path = {
+ .conf = "/opt/usr/live/%s/etc/%s.conf",
+ .image = "/opt/usr/share/live_magazine/",
+ .slave_log = "/opt/usr/share/live_magazine/log",
+ .reader = "/opt/usr/share/live_magazine/reader",
+ .always = "/opt/usr/share/live_magazine/always",
+ .script = "/opt/usr/live/%s/res/script/%s.edj",
+ .root = "/opt/usr/live/",
+ .script_port = "/usr/share/data-provider-master/plugin-script/",
+ .db = "/opt/dbspace/.livebox.db",
+ },
+
+ .ping_time = 240.0f,
+ .slave_max_load = 30,
+
+ .use_sw_backend = 0,
+ .provider_method = "pixmap",
+ .debug_mode = 0,
+ .overwrite_content = 0,
+ .com_core_thread = 1,
+ .use_xmonitor = 0,
+
+ .scale_width_factor = 1.0f,
+ .scale_height_factor = 1.0f,
+};
+
+static void conf_update_size(void)
+{
+ ecore_x_window_size_get(0, &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");
+ DbgPrint("Use xmonitor: %d\n", g_conf.use_xmonitor);
+}
+
+static void use_sw_backend_handler(char *buffer)
+{
+ g_conf.use_sw_backend = !strcasecmp(buffer, "true");
+ DbgPrint("SW Backend: %d\n", g_conf.use_sw_backend);
+}
+
+static void provider_method_handler(char *buffer)
+{
+ g_conf.provider_method = strdup(buffer);
+ if (!g_conf.provider_method)
+ ErrPrint("Heap: %s\n", strerror(errno));
+
+ DbgPrint("Method: %s\n", g_conf.provider_method);
+}
+
+static void debug_mode_handler(char *buffer)
+{
+ g_conf.debug_mode = !strcasecmp(buffer, "true");
+ DbgPrint("Debug mode: %d\n", g_conf.debug_mode);
+}
+
+static void overwrite_content_handler(char *buffer)
+{
+ g_conf.overwrite_content = !strcasecmp(buffer, "true");
+ DbgPrint("Overwrite Content: %d\n", g_conf.overwrite_content);
+}
+
+static void com_core_thread_handler(char *buffer)
+{
+ g_conf.com_core_thread = !strcasecmp(buffer, "true");
+ DbgPrint("Com core thread: %d\n", g_conf.com_core_thread);
+}
+
+static void base_width_handler(char *buffer)
+{
+ if (sscanf(buffer, "%d", &g_conf.base_width) != 1)
+ ErrPrint("Failed to parse the base_width\n");
+
+ DbgPrint("Base width: %d\n", g_conf.base_width);
+}
+
+static void base_height_handler(char *buffer)
+{
+ if (sscanf(buffer, "%d", &g_conf.base_height) != 1)
+ ErrPrint("Failed to parse the base_height\n");
+ DbgPrint("Base height: %d\n", g_conf.base_height);
+}
+
+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 script_handler(char *buffer)
+{
+ g_conf.default_conf.script = strdup(buffer);
+ if (!g_conf.default_conf.script)
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgPrint("Default script: %s\n", g_conf.default_conf.script);
+}
+
+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));
+ DbgPrint("Default ABI: %s\n", g_conf.default_conf.abi);
+}
+
+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));
+ DbgPrint("Default PD Group: %s\n", g_conf.default_conf.pd_group);
+}
+
+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));
+ DbgPrint("Default content: %s\n", g_conf.default_content);
+}
+
+static void default_title_handler(char *buffer)
+{
+ g_conf.default_title = strdup(buffer);
+ if (!g_conf.default_title)
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgPrint("Default title: %s\n", g_conf.default_title);
+}
+
+static void minimum_space_handler(char *buffer)
+{
+ if (sscanf(buffer, "%lu", &g_conf.minimum_space) != 1)
+ ErrPrint("Failed to parse the minimum_space\n");
+ DbgPrint("Minimum space: %lu\n", g_conf.minimum_space);
+}
+
+static void replace_tag_handler(char *buffer)
+{
+ g_conf.replace_tag = strdup(buffer);
+ if (!g_conf.replace_tag)
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgPrint("Replace Tag: %s\n", g_conf.replace_tag);
+}
+
+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 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");
+ DbgPrint("Max log line: %d\n", g_conf.max_log_line);
+}
+
+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");
+ DbgPrint("Max log file: %d\n", g_conf.max_log_file);
+}
+
+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");
+ DbgPrint("Flush size: %lu\n", g_conf.sqlite_flush_max);
+}
+
+static void db_path_handler(char *buffer)
+{
+ g_conf.path.db = strdup(buffer);
+ if (!g_conf.path.db)
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgPrint("DB Path: %s\n", g_conf.path.db);
+}
+
+static void reader_path_handler(char *buffer)
+{
+ g_conf.path.reader = strdup(buffer);
+ if (!g_conf.path.reader)
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgPrint("Reader Path: %s\n", g_conf.path.reader);
+}
+
+static void always_path_handler(char *buffer)
+{
+ g_conf.path.always = strdup(buffer);
+ if (!g_conf.path.always)
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgPrint("Always Path: %s\n", g_conf.path.always);
+}
+
+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));
+ DbgPrint("LOG Path: %s\n", g_conf.path.slave_log);
+}
+
+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));
+ DbgPrint("Script Port PATH: %s\n", g_conf.path.script_port);
+}
+
+static void share_path_handler(char *buffer)
+{
+ g_conf.path.image = strdup(buffer);
+ if (!g_conf.path.image)
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgPrint("Shared folder: %s\n", g_conf.path.image);
+}
+
+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");
+ DbgPrint("Max load: %d\n", g_conf.slave_max_load);
+}
+
+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 = "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 = "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 = "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 = NULL,
+ .handler = NULL,
+ },
+ };
+
+ conf_update_size();
+
+ fp = fopen("/usr/share/data-provider-master/conf.ini", "rt");
+ if (!fp) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ return -EIO;
+ }
+
+ state = START;
+ ch_idx = 0;
+ token_idx = -1;
+ buffer_idx = 0;
+ quote = 0;
+ linelen = 0;
+ do {
+ c = getc(fp);
+ if ((c == EOF) && (state == VALUE)) {
+ LOGD("[%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';
+ DbgPrint("BUFFER: [%s]\n", buffer);
+ 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);
+
+ fclose(fp);
+ return 0;
+}
+
+/* End of a file */
diff --git a/src/critical_log.c b/src/critical_log.c
new file mode 100644
index 0000000..36e7ccf
--- /dev/null
+++ b/src/critical_log.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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 <dlog.h>
+#include <Eina.h>
+
+#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;
+} s_info = {
+ .fp = NULL,
+ .file_id = 0,
+ .nr_of_lines = 0,
+ .filename = NULL,
+};
+
+
+
+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) + 20;
+ filename = malloc(namelen);
+ if (filename) {
+ snprintf(filename, namelen, "%s/%d_%s", SLAVE_LOG_PATH, s_info.file_id, s_info.filename);
+
+ if (s_info.fp)
+ fclose(s_info.fp);
+
+ 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;
+ struct timeval tv;
+
+ if (!s_info.fp)
+ return -EIO;
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }
+
+ fprintf(s_info.fp, "%d %lu.%lu [%s:%d] ", getpid(), tv.tv_sec, tv.tv_usec, util_basename((char *)func), line);
+
+ va_start(ap, fmt);
+ ret = vfprintf(s_info.fp, fmt, ap);
+ va_end(ap);
+
+ s_info.nr_of_lines++;
+ rotate_log();
+ return ret;
+}
+
+
+
+HAPI int critical_log_init(const char *name)
+{
+ int namelen;
+ char *filename;
+
+ if (s_info.fp)
+ return 0;
+
+ s_info.filename = strdup(name);
+ if (!s_info.filename) {
+ ErrPrint("Failed to create a log file\n");
+ return -ENOMEM;
+ }
+
+ namelen = strlen(name) + strlen(SLAVE_LOG_PATH) + 20;
+
+ filename = malloc(namelen);
+ if (!filename) {
+ ErrPrint("Failed to create a log file\n");
+ DbgFree(s_info.filename);
+ s_info.filename = NULL;
+ return -ENOMEM;
+ }
+
+ snprintf(filename, namelen, "%s/%d_%s", SLAVE_LOG_PATH, s_info.file_id, name);
+
+ 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 -EIO;
+ }
+
+ DbgFree(filename);
+ return 0;
+}
+
+
+
+HAPI int critical_log_fini(void)
+{
+ if (s_info.filename) {
+ DbgFree(s_info.filename);
+ s_info.filename = NULL;
+ }
+
+ if (s_info.fp) {
+ fclose(s_info.fp);
+ s_info.fp = NULL;
+ }
+
+ return 0;
+}
+
+
+
+/* End of a file */
diff --git a/src/dead_monitor.c b/src/dead_monitor.c
new file mode 100644
index 0000000..476139b
--- /dev/null
+++ b/src/dead_monitor.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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) {
+ if (slave_state(slave) == SLAVE_REQUEST_TO_TERMINATE)
+ slave = slave_deactivated(slave);
+ else if (slave_state(slave) != SLAVE_TERMINATED)
+ slave = slave_deactivated_by_fault(slave);
+ }
+
+ DbgPrint("Slave pointer: %p (0 means deleted)\n", slave);
+ return 0;
+ }
+
+ client = client_find_by_rpc_handle(handle);
+ if (client) {
+ if (client_pid(client) != (pid_t)-1)
+ client_deactivated_by_fault(client);
+
+ return 0;
+ }
+
+ liveinfo = liveinfo_find_by_handle(handle);
+ if (liveinfo) {
+ liveinfo_destroy(liveinfo);
+ return 0;
+ }
+
+ DbgPrint("This is not my favor: %d\n", handle);
+ 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/fault_manager.c b/src/fault_manager.c
new file mode 100644
index 0000000..89c2a74
--- /dev/null
+++ b/src/fault_manager.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h> /* free */
+
+#include <gio/gio.h>
+
+#include <Eina.h>
+#include <packet.h>
+#include <dlog.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"
+
+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];
+
+ snprintf(filename, sizeof(filename), "%s/slave.%d", SLAVE_LOG_PATH, slave_pid(slave));
+
+ unlink(filename);
+}
+
+static char *check_log_file(struct slave_node *slave)
+{
+ char pkgname[BUFSIZ];
+ const char *pattern = "liblive-";
+ char *ptr;
+ FILE *fp;
+ int i;
+ 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(pkgname, sizeof(pkgname), fp);
+ fclose(fp);
+ if (ptr != pkgname) {
+ ErrPrint("Invalid log\n");
+ return NULL;
+ }
+
+ for (i = 0; pattern[i] && (pattern[i] == pkgname[i]); i++); /*!< Check pattern of filename */
+ if (strlen(pattern) != i) {
+ ErrPrint("Pattern is not matched: %d\n", i);
+ return NULL;
+ }
+
+ ptr = pkgname + i;
+ i = strlen(ptr) - 3; /* Skip the ".so" */
+ if (i <= 0 || strcmp(ptr + i, ".so")) {
+ ErrPrint("Extension is not matched\n");
+ return NULL;
+ }
+
+ ptr[i] = '\0'; /*!< Truncate tailer ".so" */
+ if (unlink(filename) < 0)
+ ErrPrint("Failed to unlink %s\n", filename);
+
+ return strdup(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);
+ DbgPrint("Fault package: %s\n", pkgname);
+}
+
+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);
+ DbgPrint("Fault package: %s\n", pkgname);
+}
+
+static inline void dump_fault_info(const char *name, pid_t pid, const char *pkgname, const char *filename, const char *funcname)
+{
+ ErrPrint("Fault processing ====\n");
+ ErrPrint("Slavename: %s[%d]\n", name, pid);
+ ErrPrint("Package: %s\n", pkgname);
+ ErrPrint("Filename: %s\n", filename);
+ ErrPrint("Funcname: %s\n", 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 -ENOENT;
+
+ ret = package_set_fault_info(pkg, util_timestamp(), id, func);
+ if (ret < 0)
+ return -EFAULT;
+
+ 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 0;
+}
+
+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) {
+ int ret;
+ ret = package_set_fault_info(pkg, util_timestamp(), NULL, NULL);
+ dump_fault_info(slave_name(slave), slave_pid(slave), pkgname, "", "");
+ ErrPrint("Set fault %s(%d)\n", !ret ? "Success" : "Failed", ret);
+ 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) {
+ int ret;
+ ret = package_set_fault_info(pkg, util_timestamp(), NULL, NULL);
+ dump_fault_info(slave_name(slave), slave_pid(slave), pkgname, "", "");
+ ErrPrint("Set fault %s(%d)\n", !ret ? "Success" : "Failed", ret);
+ 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) {
+ int ret;
+ ret = package_set_fault_info(pkg, info->timestamp, info->filename, info->func);
+ fault_broadcast_info(info->pkgname, info->filename, info->func);
+ ErrPrint("Set fault %s(%d)\n", !ret ? "Success" : "Failed", ret);
+ } 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 -ENOMEM;
+
+ info->slave = slave;
+
+ info->pkgname = strdup(pkgname);
+ if (!info->pkgname) {
+ DbgFree(info);
+ return -ENOMEM;
+ }
+
+ info->filename = strdup(filename);
+ if (!info->filename) {
+ DbgFree(info->pkgname);
+ DbgFree(info);
+ return -ENOMEM;
+ }
+
+ info->func = strdup(func);
+ if (!info->func) {
+ DbgFree(info->filename);
+ DbgFree(info->pkgname);
+ DbgFree(info);
+ return -ENOMEM;
+ }
+
+ info->timestamp = util_timestamp();
+
+ s_info.call_list = eina_list_append(s_info.call_list, info);
+
+ s_info.fault_mark_count++;
+ return 0;
+}
+
+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 -ENOENT;
+}
+
+/* End of a file */
diff --git a/src/fb.c b/src/fb.c
new file mode 100644
index 0000000..fa8e122
--- /dev/null
+++ b/src/fb.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <unistd.h> /* access */
+#include <errno.h>
+
+#include <dlog.h>
+#include <Ecore_Evas.h>
+#include <Evas.h>
+
+#include "util.h"
+#include "conf.h"
+#include "debug.h"
+#include "buffer_handler.h"
+#include "fb.h"
+
+int errno;
+
+struct fb_info {
+ Ecore_Evas *ee;
+
+ struct buffer_info *buffer;
+};
+
+HAPI int fb_init(void)
+{
+ return 0;
+}
+
+HAPI int fb_fini(void)
+{
+ return 0;
+}
+
+static void *alloc_fb(void *data, int size)
+{
+ struct fb_info *info = data;
+
+ DbgPrint("FB size: %d\n", size);
+
+ if (buffer_handler_load(info->buffer) < 0) {
+ ErrPrint("Failed to load buffer handler\n");
+ return NULL;
+ }
+
+ return buffer_handler_fb(info->buffer);
+}
+
+static void free_fb(void *data, void *ptr)
+{
+ struct fb_info *info = data;
+
+ if (!info->buffer) {
+ ErrPrint("Buffer is not valid (maybe already released)\n");
+ return;
+ }
+
+ if (buffer_handler_fb(info->buffer) != ptr)
+ ErrPrint("Buffer pointer is not matched\n");
+
+ (void)buffer_handler_unload(info->buffer);
+}
+
+HAPI struct fb_info *fb_create(struct inst_info *inst, int w, int h, enum buffer_type type)
+{
+ struct fb_info *info;
+
+ info = calloc(1, sizeof(*info));
+ if (!info) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ info->buffer = buffer_handler_create(inst, type, w, h, sizeof(int));
+ if (!info->buffer) {
+ ErrPrint("Failed to create a buffer\n");
+ DbgFree(info);
+ return NULL;
+ }
+
+ info->ee = NULL;
+ return info;
+}
+
+static void sw_render_pre_cb(void *data, Evas *e, void *event_info)
+{
+ struct fb_info *info = data;
+ int w;
+ int h;
+
+ buffer_handler_get_size(info->buffer, &w, &h);
+ evas_damage_rectangle_add(e, 0, 0, w, h);
+}
+
+static void sw_render_post_cb(void *data, Evas *e, void *event_info)
+{
+ void *canvas;
+ Ecore_Evas *internal_ee;
+ int x, y, w, h;
+
+ internal_ee = ecore_evas_ecore_evas_get(e);
+ if (!internal_ee) {
+ LOGD("Failed to get ecore evas\n");
+ return;
+ }
+
+ // Get a pointer of a buffer of the virtual canvas
+ canvas = (void*)ecore_evas_buffer_pixels_get(internal_ee);
+ if (!canvas) {
+ LOGD("Failed to get pixel canvas\n");
+ return;
+ }
+
+ ecore_evas_geometry_get(internal_ee, &x, &y, &w, &h);
+ evas_data_argb_unpremul(canvas, w * h);
+}
+
+static void render_pre_cb(void *data, Evas *e, void *event_info)
+{
+ fb_pixmap_render_pre(data);
+ sw_render_pre_cb(data, e, event_info);
+}
+
+static void render_post_cb(void *data, Evas *e, void *event_info)
+{
+ sw_render_post_cb(data, e, event_info);
+ fb_pixmap_render_post(data);
+}
+
+HAPI int fb_create_buffer(struct fb_info *info)
+{
+ int ow;
+ int oh;
+ Evas *e;
+
+ buffer_handler_get_size(info->buffer, &ow, &oh);
+ DbgPrint("Buffer handler size: %dx%d\n", ow, oh);
+ if (ow == 0 && oh == 0) {
+ DbgPrint("ZERO Size FB accessed\n");
+ return 0;
+ }
+
+ if (info->ee) {
+ int w = 0;
+ int h = 0;
+
+ ecore_evas_geometry_get(info->ee, NULL, NULL, &w, &h);
+ if (w != ow || h != oh) {
+ ErrPrint("EE exists, size mismatched requested (%dx%d) but (%dx%d)\n", ow, oh, w, h);
+ ecore_evas_resize(info->ee, ow, oh);
+ }
+
+ return 0;
+ }
+
+ info->ee = ecore_evas_buffer_allocfunc_new(ow, oh, alloc_fb, free_fb, info);
+ if (!info->ee) {
+ ErrPrint("Failed to create a buffer\n");
+ return -EFAULT;
+ }
+
+ e = ecore_evas_get(info->ee);
+ if (buffer_handler_type(info->buffer) == BUFFER_TYPE_PIXMAP) {
+ evas_event_callback_add(e, EVAS_CALLBACK_RENDER_PRE, render_pre_cb, info);
+ evas_event_callback_add(e, EVAS_CALLBACK_RENDER_POST, render_post_cb, info);
+
+ /*!
+ * \note
+ * ecore_evas_alpha_set tries to access the canvas buffer.
+ * Without any render_pre/render_post callback.
+ */
+ fb_pixmap_render_pre(info);
+ ecore_evas_alpha_set(info->ee, EINA_TRUE);
+ fb_pixmap_render_post(info);
+ } else {
+ evas_event_callback_add(e, EVAS_CALLBACK_RENDER_PRE, sw_render_pre_cb, info);
+ evas_event_callback_add(e, EVAS_CALLBACK_RENDER_POST, sw_render_post_cb, info);
+ ecore_evas_alpha_set(info->ee, EINA_TRUE);
+ }
+
+ return 0;
+}
+
+HAPI int fb_destroy_buffer(struct fb_info *info)
+{
+ if (!info->ee) {
+ ErrPrint("EE is not exists (Maybe ZERO byte ee?)\n");
+ return -EINVAL;
+ }
+
+ if (buffer_handler_type(info->buffer) == BUFFER_TYPE_PIXMAP) {
+ Evas *e;
+ e = ecore_evas_get(info->ee);
+ if (e) {
+ evas_event_callback_del(e, EVAS_CALLBACK_RENDER_POST, render_post_cb);
+ evas_event_callback_del(e, EVAS_CALLBACK_RENDER_PRE, render_pre_cb);
+ }
+ }
+
+ ecore_evas_free(info->ee);
+ info->ee = NULL;
+ return 0;
+}
+
+HAPI int fb_destroy(struct fb_info *info)
+{
+ fb_destroy_buffer(info);
+ DbgFree(info);
+ return 0;
+}
+
+HAPI Ecore_Evas * const fb_canvas(struct fb_info *info)
+{
+ return info->ee;
+}
+
+HAPI const char *fb_id(struct fb_info *fb)
+{
+ return fb ? buffer_handler_id(fb->buffer) : "";
+}
+
+HAPI int fb_resize(struct fb_info *info, int w, int h)
+{
+ buffer_handler_update_size(info->buffer, w, h);
+
+ if (info->ee) {
+ ecore_evas_resize(info->ee, w, h);
+ } else if (!info->ee && !info->buffer) {
+ /*!
+ * This object has no size at the initial time.
+ * Create a new buffer and use it
+ */
+ }
+
+ return 0;
+}
+
+HAPI int fb_get_size(struct fb_info *info, int *w, int *h)
+{
+ return buffer_handler_get_size(info->buffer, w, h);
+}
+
+HAPI void fb_sync(struct fb_info *info)
+{
+ buffer_handler_flush(info->buffer);
+}
+
+HAPI void *fb_pixmap_render_pre(struct fb_info *info)
+{
+ void *canvas;
+ canvas = buffer_handler_pixmap_acquire_buffer(info->buffer);
+ return canvas;
+}
+
+HAPI int fb_pixmap_render_post(struct fb_info *info)
+{
+ void *canvas;
+
+ /*!
+ * \note
+ * info->buffer == struct buffer_info
+ */
+ canvas = buffer_handler_pixmap_buffer(info->buffer);
+ return buffer_handler_pixmap_release_buffer(canvas);
+}
+
+/* End of a file */
diff --git a/src/group.c b/src/group.c
new file mode 100644
index 0000000..c0697f1
--- /dev/null
+++ b/src/group.c
@@ -0,0 +1,873 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h> /* malloc */
+#include <errno.h>
+#include <string.h> /* strdup */
+
+#include <dlog.h>
+#include <Eina.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 -ENOMEM;
+ }
+
+ option->key = strdup(key);
+ if (!option->key) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(option);
+ return -ENOMEM;
+ }
+
+ option->value = strdup(value);
+ if (!option->value) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(option->key);
+ DbgFree(option);
+ return -ENOMEM;
+ }
+
+ option->item = item;
+ item->option_list = eina_list_append(item->option_list, option);
+ return 0;
+}
+
+HAPI int group_destroy_context_info(struct context_info *info)
+{
+ struct category *category;
+
+ category = info->category;
+ if (!category) {
+ ErrPrint("No category found\n");
+ return -EINVAL;
+ }
+
+ category->info_list = eina_list_remove(category->info_list, info);
+
+ del_context_item(info);
+ DbgFree(info->pkgname);
+ DbgFree(info);
+ return 0;
+}
+
+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;
+
+ DbgPrint("Cluster %s is created\n", cluster->name);
+ 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;
+
+ DbgPrint("Category %s is created\n", category->name);
+ 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);
+ }
+
+ DbgPrint("Destroy cluster: %s\n", cluster->name);
+ 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 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+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);
+ }
+
+ DbgPrint("Destroy category: %s\n", category->name);
+ 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 0;
+}
+
+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 -ENOMEM;
+
+ tmp->tag = strdup(tag);
+ if (!tmp->tag) {
+ DbgFree(tmp);
+ return -ENOMEM;
+ }
+
+ tmp->data = data;
+ item->data_list = eina_list_append(item->data_list, tmp);
+ return 0;
+}
+
+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;
+ struct context_item *item;
+ 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 -EFAULT;
+ }
+ /* 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 -EFAULT;
+ }
+
+ 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 -EFAULT;
+ }
+
+ info = group_create_context_info(category, pkgname);
+ if (!info) {
+ ErrPrint("Failed to create ctx info\n");
+ DbgFree(name);
+ return -EFAULT;
+ }
+
+ 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 -EFAULT;
+ }
+
+ state = CONTEXT_OPTION_KEY;
+ break;
+
+ case CONTEXT_OPTION_KEY:
+ case CONTEXT_OPTION_VALUE:
+ default:
+ ErrPrint("Invalid state\n");
+ DbgFree(name);
+ return -EFAULT;
+ }
+
+ 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 -EFAULT;
+ }
+ cluster = group_find_cluster(name);
+ if (!cluster)
+ cluster = group_create_cluster(name);
+
+ if (!cluster) {
+ ErrPrint("Failed to get cluster\n");
+ DbgFree(name);
+ return -EFAULT;
+ }
+
+ state = CATEGORY;
+ break;
+
+ case CATEGORY:
+ if (is_open != 1) {
+ ErrPrint("Invalid state\n");
+ DbgFree(name);
+ return -EFAULT;
+ }
+ 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 -EFAULT;
+ }
+
+ info = group_create_context_info(category, pkgname);
+ if (!info) {
+ ErrPrint("Failed to create ctx info\n");
+ DbgFree(name);
+ return -EFAULT;
+ }
+
+ 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 -EFAULT;
+ }
+
+ info = group_create_context_info(category, pkgname);
+ if (!info) {
+ ErrPrint("Failed to create ctx info\n");
+ DbgFree(name);
+ return -EFAULT;
+ }
+ DbgPrint("Keep this syntax only for the compatibility\n");
+ } 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 -EFAULT;
+ }
+ state = CONTEXT_OPTION_KEY;
+ } else {
+ ErrPrint("Invalid state\n");
+ DbgFree(name);
+ return -EFAULT;
+ }
+
+ break;
+ case CONTEXT_OPTION_VALUE:
+ if (is_open != 3) {
+ ErrPrint("Invalid state\n");
+ DbgFree(name);
+ return -EFAULT;
+ }
+
+ 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 -EFAULT;
+ }
+
+ 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 -EFAULT;
+ }
+
+ key = get_token(ptr, &len);
+ if (!key) {
+ ErrPrint("Failed to get token\n");
+ return -EFAULT;
+ }
+
+ 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 -EFAULT;
+ }
+
+ 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 -EFAULT;
+ }
+
+ info = group_create_context_info(category, pkgname);
+ if (!info) {
+ ErrPrint("Failed to create ctx info\n");
+ DbgFree(name);
+ return -EFAULT;
+ }
+
+ DbgPrint("Keep this syntax only for the compatibility: %s\n", name);
+ 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 -EFAULT;
+ }
+
+ info = group_create_context_info(category, pkgname);
+ if (!info) {
+ ErrPrint("Failed to create ctx info\n");
+ DbgFree(name);
+ return -EFAULT;
+ }
+
+ DbgPrint("Keep this syntax only for the compatibility: %s\n", name);
+ state = CLUSTER;
+ } else if (is_open == 2) {
+ state = CATEGORY;
+ } else {
+ ErrPrint("Invalid state\n");
+ DbgFree(name);
+ return -EFAULT;
+ }
+ break;
+ case CONTEXT_OPTION_VALUE:
+ if (is_open != 2) {
+ ErrPrint("Invalid state (%s)\n", name);
+ DbgFree(name);
+ return -EFAULT;
+ }
+
+ 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 (state != CLUSTER)
+ return -EINVAL;
+
+ return 0;
+}
+
+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 0;
+}
+
+HAPI int group_init(void)
+{
+ return 0;
+}
+
+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 0;
+}
+
+/* End of a file */
diff --git a/src/instance.c b/src/instance.c
new file mode 100644
index 0000000..fc66287
--- /dev/null
+++ b/src/instance.c
@@ -0,0 +1,2596 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <dlog.h>
+#include <Ecore_Evas.h>
+#include <Eina.h>
+#include <gio/gio.h>
+#include <Ecore.h>
+
+#include <packet.h>
+#include <com-core_packet.h>
+#include <livebox-service.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 "fb.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 change_group_cbdata {
+ struct inst_info *inst;
+ char *cluster;
+ char *category;
+};
+
+struct period_cbdata {
+ struct inst_info *inst;
+ double period;
+};
+
+struct inst_info {
+ struct pkg_info *info;
+
+ enum instance_state state; /*!< Represents current state */
+ enum instance_state requested_state; /*!< Only ACTIVATED | DESTROYED is acceptable */
+ int changing_state;
+
+ char *id;
+ double timestamp;
+
+ char *content;
+ char *cluster;
+ char *category;
+ char *title;
+ int is_pinned_up;
+ double sleep_at;
+
+ enum livebox_visible_state visible;
+
+ struct {
+ int width;
+ int height;
+ double priority;
+
+ union {
+ struct script_info *script;
+ struct buffer_info *buffer;
+ } canvas;
+
+ const char *auto_launch;
+ int timeout;
+ 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 */
+};
+
+#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);
+ DbgPrint("Compensated: %lf\n", delay);
+
+ if (inst->sleep_at == 0.0f)
+ return;
+
+ sleep_time = util_timestamp() - inst->sleep_at;
+ if (sleep_time > pending) {
+ DbgPrint("Update time elapsed\n");
+ (void)update_timer_cb(inst);
+ }
+
+ inst->sleep_at = 0.0f;
+}
+
+static inline void timer_freeze(struct inst_info *inst)
+{
+ struct timeval tv;
+ ecore_timer_freeze(inst->update_timer);
+
+ if (ecore_timer_interval_get(inst->update_timer) <= 1.0f)
+ return;
+
+ gettimeofday(&tv, NULL);
+ inst->sleep_at = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f;
+}
+
+
+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)) {
+ DbgPrint("Not found\n");
+ return -ENOENT;
+ }
+
+ 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_unref(inst);
+ return -1; /*!< Remove this callback from the cb list */
+}
+
+static inline 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 -EFAULT;
+ }
+
+ return slave_rpc_request_only(package_slave(inst->info), package_name(inst->info), packet, 0);
+}
+
+/*! \TODO Wake up the freeze'd timer */
+static inline 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 -EFAULT;
+ }
+
+ 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 = -EINVAL;
+ break;
+ }
+
+ DbgPrint("Visible state is recovered to %d\n", ret);
+ return ret;
+}
+
+HAPI void instance_send_resized_event(struct inst_info *inst, int is_pd, int w, int h, int status)
+{
+ struct packet *packet;
+ const char *pkgname;
+ const char *id;
+
+ pkgname = package_name(inst->info);
+ id = inst->id;
+
+ DbgPrint("Size is changed to %dx%d (%s) %s\n", w, h, id, is_pd ? "pd" : "lb");
+
+ packet = packet_create_noack("size_changed", "ssiiii", pkgname, id, is_pd, w, h, status);
+ if (packet)
+ CLIENT_SEND_EVENT(inst, packet);
+ else
+ ErrPrint("Failed to send size changed event\n");
+}
+
+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 0;
+ }
+
+ lb_type = package_lb_type(inst->info);
+ pd_type = package_pd_type(inst->info);
+
+ if (lb_type == LB_TYPE_SCRIPT)
+ lb_file = fb_id(script_handler_fb(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 = fb_id(script_handler_fb(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,
+ inst->lb.auto_launch,
+ 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 -EFAULT;
+ }
+
+ 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 0;
+}
+
+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 = fb_id(script_handler_fb(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 = fb_id(script_handler_fb(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,
+ inst->lb.auto_launch,
+ 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 -EFAULT;
+ }
+
+ return CLIENT_SEND_EVENT(inst, packet);
+}
+
+HAPI int instance_unicast_deleted_event(struct inst_info *inst, struct client_node *client)
+{
+ struct packet *packet;
+
+ if (!client) {
+ client = inst->client;
+ if (!client)
+ return -EINVAL;
+ }
+
+ packet = packet_create_noack("deleted", "ssd", package_name(inst->info), inst->id, inst->timestamp);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return -EFAULT;
+ }
+
+ return client_rpc_async_request(client, packet);
+}
+
+static int instance_broadcast_deleted_event(struct inst_info *inst)
+{
+ struct packet *packet;
+ struct client_node *client;
+ Eina_List *l;
+ Eina_List *n;
+ int ret;
+
+ packet = packet_create_noack("deleted", "ssd", package_name(inst->info), inst->id, inst->timestamp);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return -EFAULT;
+ }
+
+ 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);
+ return 0;
+}
+
+static int send_pd_destroyed_to_client(struct inst_info *inst, int status)
+{
+ struct packet *packet;
+
+ packet = packet_create_noack("pd_destroyed", "ssi", package_name(inst->info), inst->id, status);
+ if (!packet) {
+ ErrPrint("Failed to create a packet\n");
+ return -EFAULT;
+ }
+
+ return CLIENT_SEND_EVENT(inst, packet);
+}
+
+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;
+
+ 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 (inst->pd.need_to_send_close_event)
+ send_pd_destroyed_to_client(inst, 0);
+
+ if (lb_type == LB_TYPE_SCRIPT) {
+ script_handler_unload(inst->lb.canvas.script, 0);
+ script_handler_destroy(inst->lb.canvas.script);
+ } else if (lb_type == LB_TYPE_BUFFER) {
+ buffer_handler_unload(inst->lb.canvas.buffer);
+ buffer_handler_destroy(inst->lb.canvas.buffer);
+ }
+
+ if (pd_type == PD_TYPE_SCRIPT) {
+ script_handler_unload(inst->pd.canvas.script, 1);
+ script_handler_destroy(inst->pd.canvas.script);
+ } else if (pd_type == PD_TYPE_BUFFER) {
+ buffer_handler_unload(inst->pd.canvas.buffer);
+ buffer_handler_destroy(inst->pd.canvas.buffer);
+ }
+
+ 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);
+
+ /*!
+ * \note
+ *
+ * inst->lb.auto_launch
+ *
+ * will be released by the package object
+ * it is readonly value for instances
+ */
+ DbgFree(inst->category);
+ DbgFree(inst->cluster);
+ DbgFree(inst->content);
+ DbgFree(inst->title);
+ util_unlink(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;
+
+ DbgPrint("Update instance %s (%s) %s/%s\n", package_name(inst->info), inst->id, inst->cluster, inst->category);
+ slave_rpc_request_update(package_name(inst->info), inst->id, inst->cluster, inst->category);
+ 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 -ENOENT;
+ }
+
+ 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 -ENOMEM;
+ }
+
+ snprintf(inst->id, len, SCHEMA_FILE "%s%s_%d_%lf.png", IMAGE_PATH, package_name(info), client_pid(inst->client), inst->timestamp);
+ inst->lb.auto_launch = package_auto_launch(info);
+
+ instance_set_pd_info(inst, package_pd_width(info), package_pd_height(info));
+
+ inst->lb.timeout = package_timeout(info);
+ inst->lb.period = package_period(info);
+
+ inst->info = info;
+
+ if (package_secured(info)) {
+ DbgPrint("Register the update timer for secured livebox [%s]\n", package_name(info));
+ 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 */
+ }
+
+ return 0;
+}
+
+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);
+ client_event_callback_add(inst->client, CLIENT_EVENT_DEACTIVATE, client_deactivated_cb, inst);
+ }
+
+ if (fork_package(inst, pkgname) < 0) {
+ client_event_callback_del(inst->client, CLIENT_EVENT_DEACTIVATE, client_deactivated_cb, inst);
+ 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_state_reset(inst);
+ instance_destroy(inst);
+ return NULL;
+ }
+
+ slave_load_instance(package_slave(inst->info));
+
+ if (instance_activate(inst) < 0) {
+ instance_state_reset(inst);
+ instance_destroy(inst);
+ 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;
+ struct pkg_info *info;
+ int ret;
+
+ /*!
+ * \note
+ * In this callback, we cannot trust the "client" information.
+ * It could be cleared before reach to here.
+ */
+
+ if (!packet) {
+ DbgPrint("Consuming a request of a dead process\n");
+ /*!
+ * \note
+ * The instance_reload will care this.
+ * And it will be called from the slave activate callback.
+ */
+ inst->changing_state = 0;
+ instance_unref(inst);
+ return;
+ }
+
+ if (packet_get(packet, "i", &ret) != 1) {
+ ErrPrint("Invalid argument\n");
+ inst->changing_state = 0;
+ instance_unref(inst);
+ return;
+ }
+
+ if (inst->state == INST_DESTROYED) {
+ /*!
+ * \note
+ * Already destroyed.
+ * Do nothing at here anymore.
+ */
+ inst->changing_state = 0;
+ instance_unref(inst);
+ return;
+ }
+
+ switch (ret) {
+ case 0:
+ /*!
+ * \note
+ * Successfully unloaded
+ */
+ switch (inst->requested_state) {
+ case INST_ACTIVATED:
+ DbgPrint("REQ: ACTIVATED\n");
+ instance_state_reset(inst);
+ instance_reactivate(inst);
+ break;
+ case INST_DESTROYED:
+ info = inst->info;
+ instance_broadcast_deleted_event(inst);
+ instance_state_reset(inst);
+ instance_destroy(inst);
+ DbgPrint("== %s\n", package_name(info));
+ default:
+ /*!< Unable to reach here */
+ break;
+ }
+
+ break;
+ case -EINVAL:
+ /*!
+ * \note
+ * Slave has no instance of this package.
+ */
+ case -ENOENT:
+ /*!
+ * \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 -ENOENT, -EINVAL, or 0.
+ * but care this exceptional case.
+ */
+ DbgPrint("[%s] instance destroying ret(%d)\n", package_name(inst->info), ret);
+ info = inst->info;
+ instance_broadcast_deleted_event(inst);
+ instance_state_reset(inst);
+ instance_destroy(inst);
+ break;
+ }
+
+ 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;
+ struct pkg_info *info;
+ enum lb_type lb_type;
+ enum pd_type pd_type;
+ int ret;
+ const char *content;
+ const char *title;
+ int is_pinned_up;
+
+ if (!packet) {
+ DbgPrint("Consuming a request of a dead process\n");
+ /*!
+ * \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;
+
+ DbgPrint("Update content info %s\n", 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;
+
+ DbgPrint("Update title info %s\n", 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);
+ break;
+ case INST_ACTIVATED:
+ inst->is_pinned_up = is_pinned_up;
+ info = inst->info;
+ lb_type = package_lb_type(info);
+ pd_type = package_pd_type(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", util_uri_to_path(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", util_uri_to_path(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:
+ info = inst->info;
+ DbgPrint("[%s] instance destroying ret(%d)\n", package_name(info), ret);
+ instance_broadcast_deleted_event(inst);
+ instance_state_reset(inst);
+ instance_destroy(inst);
+ 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) {
+ DbgPrint("Consuming a request of a dead process\n");
+ /*!
+ * \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;
+ }
+
+ 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,
+ * so just increase the loaded instance counter
+ * After that, do reset jobs.
+ */
+ instance_set_lb_info(inst, w, h, priority, content, title);
+
+ inst->state = INST_ACTIVATED;
+
+ switch (inst->requested_state) {
+ case INST_DESTROYED:
+ instance_unicast_deleted_event(inst, NULL);
+ instance_state_reset(inst);
+ instance_destroy(inst);
+ 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);
+ }
+
+ if (package_pd_type(inst->info) == PD_TYPE_SCRIPT) {
+ if (inst->pd.width == 0 && inst->pd.height == 0)
+ instance_set_pd_info(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);
+ }
+
+ instance_broadcast_created_event(inst);
+
+ instance_thaw_updator(inst);
+ break;
+ }
+ break;
+ default:
+ DbgPrint("[%s] instance destroying ret(%d)\n", package_name(inst->info), ret);
+ instance_unicast_deleted_event(inst, NULL);
+ instance_state_reset(inst);
+ instance_destroy(inst);
+ break;
+ }
+
+out:
+ inst->changing_state = 0;
+ instance_unref(inst);
+}
+
+HAPI int instance_create_pd_buffer(struct inst_info *inst)
+{
+ if (inst->pd.width == 0 && inst->pd.height == 0)
+ instance_set_pd_info(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, sizeof(int));
+ 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)
+{
+ 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, sizeof(int));
+ if (!inst->lb.canvas.buffer)
+ ErrPrint("Failed to create LB\n");
+ }
+
+ return !!inst->lb.canvas.buffer;
+}
+
+HAPI int instance_destroy(struct inst_info *inst)
+{
+ struct packet *packet;
+
+ if (!inst) {
+ ErrPrint("Invalid instance handle\n");
+ return -EINVAL;
+ }
+
+ switch (inst->state) {
+ case INST_REQUEST_TO_ACTIVATE:
+ case INST_REQUEST_TO_DESTROY:
+ case INST_REQUEST_TO_REACTIVATE:
+ inst->requested_state = INST_DESTROYED;
+ return 0;
+ case INST_INIT:
+ inst->state = INST_DESTROYED;
+ inst->requested_state = INST_DESTROYED;
+ instance_unref(inst);
+ return 0;
+ case INST_DESTROYED:
+ inst->requested_state = INST_DESTROYED;
+ return 0;
+ default:
+ break;
+ }
+
+ packet = packet_create("delete", "ss", package_name(inst->info), inst->id);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return -EFAULT;
+ }
+
+ 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);
+}
+
+/* Client Deactivated Callback */
+static int pd_buffer_close_cb(struct client_node *client, void *inst)
+{
+ int ret;
+
+ ret = instance_slave_close_pd(inst, client);
+ DbgPrint("Forcely close the PD ret: %d\n", ret);
+ 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);
+ DbgPrint("Unload script: %d\n", ret);
+
+ ret = instance_slave_close_pd(inst, client);
+ DbgPrint("Forcely close the PD ret: %d\n", ret);
+
+ 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 -EINVAL;
+ }
+
+ if (inst->state == INST_DESTROYED)
+ return 0;
+
+ 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);
+ }
+
+ inst->state = INST_INIT;
+ inst->requested_state = INST_INIT;
+ return 0;
+}
+
+HAPI int instance_reactivate(struct inst_info *inst)
+{
+ struct packet *packet;
+ int ret;
+
+ if (!inst) {
+ ErrPrint("Invalid instance handle\n");
+ return -EINVAL;
+ }
+
+ if (package_is_fault(inst->info)) {
+ DbgPrint("Fault package [%s]\n", package_name(inst->info));
+ return -EFAULT;
+ }
+
+ switch (inst->state) {
+ case INST_REQUEST_TO_DESTROY:
+ case INST_REQUEST_TO_ACTIVATE:
+ case INST_REQUEST_TO_REACTIVATE:
+ inst->requested_state = INST_ACTIVATED;
+ return 0;
+ case INST_DESTROYED:
+ case INST_ACTIVATED:
+ return 0;
+ case INST_INIT:
+ default:
+ break;
+ }
+
+ packet = packet_create("renew", "sssiidssiis",
+ package_name(inst->info),
+ inst->id,
+ inst->content,
+ inst->lb.timeout,
+ !!package_lb_path(inst->info),
+ inst->lb.period,
+ inst->cluster,
+ inst->category,
+ inst->lb.width, inst->lb.height,
+ package_abi(inst->info));
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return -EFAULT;
+ }
+
+ ret = slave_activate(package_slave(inst->info));
+ if (ret < 0 && ret != -EALREADY) {
+ /*!
+ * \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 -EINVAL;
+ }
+
+ if (package_is_fault(inst->info)) {
+ DbgPrint("Fault package [%s]\n", package_name(inst->info));
+ return -EFAULT;
+ }
+
+ switch (inst->state) {
+ case INST_REQUEST_TO_REACTIVATE:
+ case INST_REQUEST_TO_ACTIVATE:
+ case INST_REQUEST_TO_DESTROY:
+ inst->requested_state = INST_ACTIVATED;
+ return 0;
+ case INST_ACTIVATED:
+ case INST_DESTROYED:
+ return 0;
+ case INST_INIT:
+ default:
+ break;
+ }
+
+ packet = packet_create("new", "sssiidssisii",
+ package_name(inst->info),
+ inst->id,
+ inst->content,
+ inst->lb.timeout,
+ !!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 -EFAULT;
+ }
+
+ ret = slave_activate(package_slave(inst->info));
+ if (ret < 0 && ret != -EALREADY) {
+ /*!
+ * \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 void instance_lb_updated(const char *pkgname, const char *id)
+{
+ struct inst_info *inst;
+
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst)
+ return;
+
+ instance_lb_updated_by_instance(inst);
+}
+
+HAPI void instance_lb_updated_by_instance(struct inst_info *inst)
+{
+ struct packet *packet;
+ const char *id;
+ enum lb_type lb_type;
+ const char *title;
+ const char *content;
+
+ 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 = fb_id(script_handler_fb(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 = "";
+
+ packet = packet_create_noack("lb_updated", "sssiidss",
+ package_name(inst->info), inst->id, id,
+ inst->lb.width, inst->lb.height, inst->lb.priority, content, title);
+ 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_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 = fb_id(script_handler_fb(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 void instance_set_lb_info(struct inst_info *inst, int w, int h, 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;
+
+ inst->lb.width = w;
+ inst->lb.height = h;
+}
+
+HAPI void instance_set_pd_info(struct inst_info *inst, int w, int h)
+{
+ 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 = -EINVAL;
+ goto out;
+ }
+
+ if (packet_get(packet, "is", &ret, &content) != 2) {
+ /*!
+ * \todo
+ * Send pinup failed event to client
+ */
+ ret = -EINVAL;
+ 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 = -ENOMEM;
+ 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 -EINVAL;
+ }
+
+ if (package_is_fault(inst->info)) {
+ DbgPrint("Fault package [%s]\n", package_name(inst->info));
+ return -EFAULT;
+ }
+
+ if (!package_pinup(inst->info))
+ return -EINVAL;
+
+ if (pinup == inst->is_pinned_up)
+ return -EINVAL;
+
+ cbdata = malloc(sizeof(*cbdata));
+ if (!cbdata)
+ return -ENOMEM;
+
+ 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 -EFAULT;
+ }
+
+ 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 -EINVAL;
+
+ DbgPrint("Freeze the update timer (%s)\n", inst->id);
+ timer_freeze(inst);
+ return 0;
+}
+
+HAPI int instance_thaw_updator(struct inst_info *inst)
+{
+ if (!inst->update_timer)
+ return -EINVAL;
+
+ if (client_is_all_paused() || setting_is_lcd_off()) {
+ DbgPrint("Skip thaw (%s)\n", inst->id);
+ return -EINVAL;
+ }
+
+ if (inst->visible == LB_HIDE_WITH_PAUSE) {
+ DbgPrint("Live box is invisible (%s)\n", inst->id);
+ return -EINVAL;
+ }
+
+ DbgPrint("Thaw the update timer (%s)\n", inst->id);
+ timer_thaw(inst);
+ return 0;
+}
+
+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) {
+ DbgPrint("Visibility has no changed\n");
+ return 0;
+ }
+
+ 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 -EINVAL;
+ }
+
+ return 0;
+}
+
+static void resize_cb(struct slave_node *slave, const struct packet *packet, void *data)
+{
+ struct resize_cbdata *cbdata = data;
+ int ret;
+
+ if (!packet) {
+ ErrPrint("Invalid packet\n");
+ instance_send_resized_event(cbdata->inst, IS_LB, cbdata->inst->lb.width, cbdata->inst->lb.height, -EFAULT);
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata);
+ return;
+ }
+
+ if (packet_get(packet, "i", &ret) != 1) {
+ ErrPrint("Invalid parameter\n");
+ instance_send_resized_event(cbdata->inst, IS_LB, cbdata->inst->lb.width, cbdata->inst->lb.height, -EINVAL);
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata);
+ return;
+ }
+
+ if (ret == 0) {
+ /*!
+ * \note
+ * else waiting the first update with new size
+ */
+ } else {
+ DbgPrint("Livebox rejects the new size: %dx%d (%d)\n", 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 -EINVAL;
+ }
+
+ if (package_is_fault(inst->info)) {
+ ErrPrint("Fault package: %s\n", package_name(inst->info));
+ return -EFAULT;
+ }
+
+ cbdata = malloc(sizeof(*cbdata));
+ if (!cbdata) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ 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 -EFAULT;
+ }
+
+ 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 = -EFAULT;
+ goto out;
+ }
+
+ if (packet_get(packet, "i", &ret) != 1) {
+ ret = -EINVAL;
+ 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);
+
+ DbgPrint("Update period is changed to %lf from %lf\n", period, inst->lb.period);
+
+ 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 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 -EINVAL;
+ }
+
+ if (package_is_fault(inst->info)) {
+ DbgPrint("Fault package [%s]\n", package_name(inst->info));
+ return -EFAULT;
+ }
+
+ 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 -ENOMEM;
+ }
+
+ 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 0;
+ }
+
+ 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 -EFAULT;
+ }
+
+ 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 -EINVAL;
+ }
+
+ if (package_is_fault(inst->info)) {
+ DbgPrint("Fault package [%s]\n", package_name(inst->info));
+ return -EFAULT;
+ }
+
+ /* 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 -EFAULT;
+ }
+
+ 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;
+ int ret;
+
+ pkgname = package_name(instance_package(inst));
+ id = instance_id(inst);
+ if (!pkgname || !id) {
+ ErrPrint("Invalid instance\n");
+ return -EINVAL;
+ }
+
+ slave = package_slave(instance_package(inst));
+ if (!slave) {
+ ErrPrint("Slave is not valid\n");
+ return -EINVAL;
+ }
+
+ packet = packet_create_noack("script", "ssssddddddi",
+ pkgname, id,
+ signal, part,
+ sx, sy, ex, ey,
+ x, y, down);
+ if (!packet) {
+ ErrPrint("Failed to create param\n");
+ return -EFAULT;
+ }
+
+ DbgPrint("Signal emit: %s(%s), %s(%s), %lf, %lf, %lf, %lf, %lfx%lf, %d\n", pkgname, id, signal, part, sx, sy, ex, ey, x, y, down);
+ ret = slave_rpc_request_only(slave, pkgname, packet, 0);
+ return ret;
+}
+
+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 -EINVAL;
+ }
+
+ if (package_is_fault(inst->info)) {
+ DbgPrint("Fault package [%s]\n", package_name(inst->info));
+ return -EFAULT;
+ }
+
+ 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 -EFAULT;
+ }
+
+ 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 = -EFAULT;
+ goto out;
+ }
+
+ if (packet_get(packet, "i", &ret) != 1) {
+ ErrPrint("Invalid packet\n");
+ DbgFree(cbdata->cluster);
+ DbgFree(cbdata->category);
+ ret = -EINVAL;
+ 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 -EINVAL;
+ }
+
+ if (package_is_fault(inst->info)) {
+ DbgPrint("Fault package [%s]\n", package_name(inst->info));
+ return -EFAULT;
+ }
+
+ cbdata = malloc(sizeof(*cbdata));
+ if (!cbdata) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ cbdata->cluster = strdup(cluster);
+ if (!cbdata->cluster) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(cbdata);
+ return -ENOMEM;
+ }
+
+ cbdata->category = strdup(category);
+ if (!cbdata->category) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(cbdata->cluster);
+ DbgFree(cbdata);
+ return -ENOMEM;
+ }
+
+ 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 -EFAULT;
+ }
+
+ 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 inst->lb.auto_launch;
+}
+
+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 inst->lb.timeout;
+}
+
+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)
+{
+ 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);
+ instance_state_reset(inst);
+ instance_destroy(inst);
+ 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);
+ instance_state_reset(inst);
+ instance_destroy(inst);
+ case INST_DESTROYED:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*!
+ * 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 0;
+ }
+
+ 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);
+ 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);
+ instance_state_reset(inst);
+ instance_destroy(inst);
+ } else {
+ ret = 1;
+ }
+ break;
+ case INST_DESTROYED:
+ DbgPrint("Req. to DESTROYED (%s)\n", package_name(inst->info));
+ instance_state_reset(inst);
+ instance_destroy(inst);
+ ret = 1;
+ 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);
+ break;
+ case INST_DESTROYED:
+ break;
+ }
+
+ return 0;
+ }
+
+ 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);
+ 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);
+ break;
+ default:
+ break;
+ }
+ break;
+ case INST_DESTROYED:
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+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 -EINVAL;
+ }
+ } else if (inst->pd.owner) {
+ if (inst->pd.owner != client) {
+ ErrPrint("Client is already owned\n");
+ return -EBUSY;
+ }
+ }
+
+ slave = package_slave(instance_package(inst));
+ if (!slave)
+ return -EFAULT;
+
+ info = instance_package(inst);
+ if (!info)
+ return -EINVAL;
+
+ pkgname = package_name(info);
+ id = instance_id(inst);
+
+ if (!pkgname || !id)
+ return -EINVAL;
+
+ 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 -EFAULT;
+ }
+
+ slave_freeze_ttl(slave);
+
+ ret = slave_rpc_request_only(slave, pkgname, packet, 0);
+
+ /*!
+ * \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;
+ DbgPrint("pd,show event is sent\n");
+ return ret;
+}
+
+HAPI int instance_slave_close_pd(struct inst_info *inst, struct client_node *client)
+{
+ const char *pkgname;
+ const char *id;
+ struct packet *packet;
+ struct slave_node *slave;
+ struct pkg_info *info;
+ int ret;
+
+ if (inst->pd.owner != client) {
+ ErrPrint("PD owner is not matched\n");
+ return -EINVAL;
+ }
+
+ slave = package_slave(instance_package(inst));
+ if (!slave)
+ return -EFAULT;
+
+ info = instance_package(inst);
+ if (!info)
+ return -EINVAL;
+
+ pkgname = package_name(info);
+ id = instance_id(inst);
+
+ if (!pkgname || !id)
+ return -EINVAL;
+
+ packet = packet_create_noack("pd_hide", "ss", pkgname, id);
+ if (!packet) {
+ ErrPrint("Failed to create a packet\n");
+ return -EFAULT;
+ }
+
+ slave_thaw_ttl(slave);
+
+ ret = slave_rpc_request_only(slave, pkgname, packet, 0);
+ release_resource_for_closing_pd(info, inst, client);
+ inst->pd.owner = NULL;
+ 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 -EINVAL;
+ }
+
+ switch (package_pd_type(inst->info)) {
+ case PD_TYPE_SCRIPT:
+ buf_id = fb_id(script_handler_fb(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 -EFAULT;
+ }
+
+ 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)
+{
+ if (!inst->pd.need_to_send_close_event) {
+ DbgPrint("PD is not created\n");
+ return -EINVAL;
+ }
+
+ inst->pd.need_to_send_close_event = 0;
+
+ 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 -EINVAL;
+ }
+
+ 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 -EFAULT;
+ }
+
+ instance_ref(inst);
+ inst->client_list = eina_list_append(inst->client_list, client);
+ return 0;
+}
+
+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 -EINVAL;
+ }
+
+ client_event_callback_del(client, CLIENT_EVENT_DEACTIVATE, viewer_deactivated_cb, inst);
+ viewer_deactivated_cb(client, inst);
+ return 0;
+}
+
+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 void 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;
+}
+
+HAPI void instance_fini(void)
+{
+}
+
+/* End of a file */
diff --git a/src/io.c b/src/io.c
new file mode 100644
index 0000000..061cc2d
--- /dev/null
+++ b/src/io.c
@@ -0,0 +1,857 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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 "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 inline int load_abi_table(void)
+{
+ FILE *fp;
+ int ch;
+ int idx;
+ int tag_id;
+ enum {
+ INIT = 0x0,
+ GROUP = 0x1,
+ TAG = 0x02,
+ VALUE = 0x03,
+ ERROR = 0x05,
+ } state;
+ enum {
+ PKGNAME = 0x0,
+ };
+ static const char *field[] = {
+ "package",
+ NULL,
+ };
+ const char *ptr;
+
+ char group[MAX_ABI + 1];
+ char pkgname[MAX_PKGNAME + 1];
+
+ fp = fopen("/usr/share/"PACKAGE"/abi.ini", "rt");
+ if (!fp)
+ return -EIO;
+
+ 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';
+ DbgPrint("group: %s\n", group);
+ 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;
+ DbgPrint("tag: %s\n", field[tag_id]);
+ } 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';
+ DbgPrint("value: %s\n", pkgname);
+
+ DbgPrint("Add [%s] - [%s]\n", group, pkgname);
+ 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';
+ DbgPrint("value: %s\n", pkgname);
+ DbgPrint("Add [%s] - [%s]\n", group, pkgname);
+ ret = abi_add_entry(group, pkgname);
+ if (ret != 0)
+ ErrPrint("Failed to add %s for %s\n", pkgname, group);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+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 -EIO;
+ }
+
+ 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 -EIO;
+ }
+
+ 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 -EIO;
+ }
+
+ 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 0;
+}
+
+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 -EIO;
+ }
+
+ 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 -EIO;
+ }
+
+ 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 -EIO;
+ }
+
+ 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 -EIO;
+ }
+
+ 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 -EIO;
+ }
+
+ 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);
+ DbgPrint("LB Path: %s\n", 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);
+ DbgPrint("PD Path: %s\n", 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 0;
+}
+
+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 -EIO;
+ }
+
+ 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 -EIO;
+ }
+
+ 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 0;
+}
+
+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 -EIO;
+ }
+
+ ret = sqlite3_bind_int(stmt, 1, id);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = -ENOENT;
+ 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 -EIO;
+ }
+
+ ret = sqlite3_bind_int(stmt, 1, id);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = -ENOENT;
+ 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 = -EFAULT;
+ 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 -EIO;
+ }
+
+ 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 -EIO;
+ }
+
+ 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 == -ENOENT) {
+ 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 0;
+}
+
+HAPI int io_is_exists(const char *pkgname) /* Manifest Package Name */
+{
+ sqlite3_stmt *stmt;
+ int ret;
+
+ if (!s_info.handle) {
+ ErrPrint("DB is not ready\n");
+ return -EIO;
+ }
+
+ ret = sqlite3_prepare_v2(s_info.handle, "SELECT COUNT(pkgid) FROM pkgmap WHERE appid = ?", -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgname, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ if (sqlite3_step(stmt) != SQLITE_ROW) {
+ ErrPrint("%s has no record (%s)\n", pkgname, sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ 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 *pkgname, 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 pkgid, prime FROM pkgmap", -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ } else {
+ const char *pkgid;
+ int prime;
+
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ pkgid = (const char *)sqlite3_column_text(stmt, 0);
+ if (!pkgid || !strlen(pkgid))
+ continue;
+
+ prime = (int)sqlite3_column_int(stmt, 1);
+ if (cb(pkgid, prime, data) < 0) {
+ sqlite3_reset(stmt);
+ sqlite3_finalize(stmt);
+ return -ECANCELED;
+ }
+ }
+
+ 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, -1, data) < 0) {
+ closedir(dir);
+ return -ECANCELED;
+ }
+ }
+
+ closedir(dir);
+ }
+
+ return 0;
+}
+
+HAPI int io_update_livebox_package(const char *pkgname, int (*cb)(const char *lb_pkgname, int prime, void *data), void *data)
+{
+ sqlite3_stmt *stmt;
+ char *pkgid;
+ int prime;
+ int ret;
+
+ if (!cb || !pkgname)
+ return -EINVAL;
+
+ if (!s_info.handle) {
+ ErrPrint("DB is not ready\n");
+ return -EINVAL;
+ }
+
+ 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 -EFAULT;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgname, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = 0;
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ pkgid = (char *)sqlite3_column_text(stmt, 0);
+ if (!pkgid || !strlen(pkgid))
+ continue;
+
+ prime = sqlite3_column_int(stmt, 1);
+
+ if (cb(pkgid, 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 -EIO;
+ }
+
+ 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 0;
+}
+
+static inline int db_init(void)
+{
+ int ret;
+ struct stat stat;
+
+ ret = db_util_open(DBFILE, &s_info.handle, DB_UTIL_REGISTER_HOOK_METHOD);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Failed to open a DB\n");
+ return -EIO;
+ }
+
+ if (lstat(DBFILE, &stat) < 0) {
+ db_util_close(s_info.handle);
+ s_info.handle = NULL;
+ ErrPrint("%s\n", strerror(errno));
+ 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 <= 0)
+ DbgPrint("Size is %d (But use this ;)\n", stat.st_size);
+
+ 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;
+}
+
+HAPI int io_init(void)
+{
+ int ret;
+
+ ret = db_init();
+ DbgPrint("DB initialized: %d\n", ret);
+
+ ret = load_abi_table();
+ DbgPrint("ABI table is loaded: %d\n", ret);
+
+ return 0;
+}
+
+HAPI int io_fini(void)
+{
+ int ret;
+
+ ret = abi_del_all();
+ DbgPrint("ABI table is finalized: %d\n", ret);
+
+ ret = db_fini();
+ DbgPrint("DB finalized: %d\n", ret);
+ return 0;
+}
+
+/* End of a file */
diff --git a/src/liveinfo.c b/src/liveinfo.c
new file mode 100644
index 0000000..2ff7e33
--- /dev/null
+++ b/src/liveinfo.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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 "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;
+};
+
+HAPI int liveinfo_init(void)
+{
+ return 0;
+}
+
+HAPI int liveinfo_fini(void)
+{
+ struct liveinfo *info;
+
+ EINA_LIST_FREE(s_info.info_list, info) {
+ fclose(info->fp);
+ unlink(info->fifo_name);
+ DbgFree(info);
+ }
+
+ return 0;
+}
+
+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("/usr/bin/liveinfo", &src) < 0) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ return 0;
+ }
+
+ return target.st_ino == src.st_ino;
+}
+
+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));
+ unlink(info->fifo_name);
+ 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 -EIO;
+ }
+
+ return 0;
+}
+
+HAPI int liveinfo_close_fifo(struct liveinfo *info)
+{
+ if (info->fp) {
+ fclose(info->fp);
+ info->fp = NULL;
+ }
+
+ return 0;
+}
+
+HAPI int liveinfo_destroy(struct liveinfo *info)
+{
+ s_info.info_list = eina_list_remove(s_info.info_list, info);
+ liveinfo_close_fifo(info);
+ unlink(info->fifo_name);
+ DbgFree(info);
+ return 0;
+}
+
+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..32538bd
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <Ecore.h>
+#include <Ecore_X.h>
+#include <Evas.h>
+#include <Ecore_Evas.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <aul.h>
+
+#include <packet.h>
+#include <dlog.h>
+
+#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 "conf.h"
+#include "io.h"
+#include "xmonitor.h"
+#include "setting.h"
+#include "server.h"
+#include "util.h"
+#include "debug.h"
+#include "critical_log.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) != 0) {
+ if (mkdir(SLAVE_LOG_PATH, 755) < 0)
+ ErrPrint("Failed to create %s (%s)\n", SLAVE_LOG_PATH, strerror(errno));
+ }
+
+ /*!
+ * \note
+ * Dead signal handler has to be initialized before
+ * initate package or client (slave and client).
+ *
+ * Because while creating slaves for packages.
+ * It could be crashed before complete the initation stage.
+ *
+ * Then the dead callback should be invoked to handle it properly.
+ *
+ * To enable the dead signal handler,
+ * dead_init should be done before other components are initiated.
+ */
+ ret = setting_init();
+ DbgPrint("Setting initialized: %d\n", ret);
+
+ ret = client_init();
+ DbgPrint("Client initialized: %d\n", ret);
+
+ ret = dead_init();
+ DbgPrint("Dead callback is registered: %d\n", ret);
+
+ ret = group_init();
+ DbgPrint("group init: %d\n", ret);
+
+ ret = io_init();
+ DbgPrint("Init I/O: %d\n", ret);
+
+ ret = package_init();
+ DbgPrint("pkgmgr initialized: %d\n", ret);
+
+ instance_init();
+
+ ret = xmonitor_init();
+ DbgPrint("XMonitor init is done: %d\n", ret);
+
+ ret = buffer_handler_init();
+ DbgPrint("Buffer handler init is done: %d\n", ret);
+
+ /*!
+ * \note
+ * After initiate all other sub-systtems,
+ * Enable the server socket.
+ */
+ ret = server_init();
+ DbgPrint("Server initialized: %d\n", ret);
+
+ return 0;
+}
+
+static inline int app_terminate(void)
+{
+ int ret;
+
+ ret = setting_fini();
+ DbgPrint("Finalize setting : %d\n", ret);
+
+ xmonitor_fini();
+
+ instance_fini();
+
+ ret = package_fini();
+ DbgPrint("Finalize package info: %d\n", ret);
+
+ ret = client_fini();
+ DbgPrint("Finalize client connections : %d\n", ret);
+
+ ret = server_fini();
+ DbgPrint("Finalize dbus: %d\n", ret);
+
+ ret = dead_fini();
+ DbgPrint("dead signal handler finalized: %d\n", ret);
+
+ ret = io_fini();
+ DbgPrint("IO finalized: %d\n", ret);
+
+ ret = group_fini();
+ DbgPrint("Group finalized: %d\n", ret);
+
+ DbgPrint("Terminated\n");
+ return 0;
+}
+
+static void signal_handler(int signum, siginfo_t *info, void *unused)
+{
+ int fd;
+ CRITICAL_LOG("Terminated(SIGTERM)\n");
+ fd = creat("/tmp/.stop.provider", 0644);
+ if (fd > 0)
+ close(fd);
+ exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+ struct sigaction act;
+ int ret;
+
+ /*!
+ * How could we care this return values?
+ * Is there any way to print something on the screen?
+ */
+ ret = critical_log_init(util_basename(argv[0]));
+ if (ret < 0)
+ fprintf(stderr, "Failed to init the critical log\n");
+
+#if defined(FLOG)
+ __file_log_fp = fopen("/tmp/live.log", "w+t");
+ if (!__file_log_fp)
+ __file_log_fp = fdopen(1, "w+t");
+#endif
+ /* appcore_agent_terminate */
+ if (ecore_init() <= 0) {
+ CRITICAL_LOG("Failed to initiate ecore\n");
+ critical_log_fini();
+ return -EFAULT;
+ }
+
+ act.sa_sigaction = signal_handler;
+ act.sa_flags = SA_SIGINFO;
+
+ ret = sigemptyset(&act.sa_mask);
+ if (ret < 0)
+ CRITICAL_LOG("Failed to do sigemptyset: %s\n", strerror(errno));
+
+ ret = sigaddset(&act.sa_mask, SIGTERM);
+ if (ret < 0)
+ CRITICAL_LOG("Failed to mask the SIGTERM: %s\n", strerror(errno));
+
+ ret = sigaction(SIGTERM, &act, NULL);
+ if (ret < 0)
+ CRITICAL_LOG("Failed to add sigaction: %s\n", strerror(errno));
+
+ if (ecore_x_init(NULL) <= 0) {
+ CRITICAL_LOG("Failed to ecore x init\n");
+ ecore_shutdown();
+ critical_log_fini();
+ return -EFAULT;
+ }
+
+ ecore_app_args_set(argc, (const char **)argv);
+
+ if (evas_init() <= 0) {
+ CRITICAL_LOG("Failed to init evas return count is below than 0\n");
+ ecore_x_shutdown();
+ ecore_shutdown();
+ critical_log_fini();
+ return -EFAULT;
+ }
+
+ if (ecore_evas_init() <= 0) {
+ CRITICAL_LOG("Failed to init ecore_evas\n");
+ evas_shutdown();
+ ecore_x_shutdown();
+ ecore_shutdown();
+ critical_log_fini();
+ return -EFAULT;
+ }
+
+ g_type_init();
+
+ conf_loader();
+
+ /*!
+ * \note
+ * Clear old contents files before start the master provider.
+ */
+ (void)util_unlink_files(ALWAYS_PATH);
+ (void)util_unlink_files(READER_PATH);
+ (void)util_unlink_files(IMAGE_PATH);
+ (void)util_unlink_files(SLAVE_LOG_PATH);
+
+ script_init();
+
+ app_create();
+ ecore_main_loop_begin();
+ app_terminate();
+
+ script_fini();
+
+ ecore_evas_shutdown();
+ evas_shutdown();
+
+ ecore_x_shutdown();
+ ecore_shutdown();
+ critical_log_fini();
+
+#if defined(FLOG)
+ if (__file_log_fp)
+ fclose(__file_log_fp);
+#endif
+ return 0;
+}
+
+/* End of a file */
diff --git a/src/package.c b/src/package.c
new file mode 100644
index 0000000..5b76c64
--- /dev/null
+++ b/src/package.c
@@ -0,0 +1,1469 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h> /* strcmp */
+#include <stdlib.h> /* free */
+
+#include <dlog.h>
+#include <Eina.h>
+#include <Ecore_Evas.h>
+
+#include <packet.h>
+
+#include "debug.h"
+#include "util.h"
+#include "parser.h"
+#include "conf.h"
+#include "slave_life.h"
+#include "slave_rpc.h"
+#include "client_life.h"
+#include "package.h"
+#include "fault_manager.h"
+#include "instance.h"
+#include "script_handler.h"
+#include "group.h"
+#include "abi.h"
+#include "io.h"
+#include "pkgmgr.h"
+#include "xmonitor.h"
+
+int errno;
+
+struct fault_info {
+ double timestamp;
+ char *filename;
+ char *function;
+};
+
+/*!
+ * pkg_info describes the loaded package.
+ */
+
+struct pkg_info {
+ char *pkgname;
+
+ struct {
+ enum lb_type type;
+
+ union {
+ struct {
+ char *path;
+ char *group;
+ } script;
+
+ struct {
+ /*!< Reserved for future use */
+ } file;
+
+ struct {
+ /*!< Reserved for future use */
+ } text;
+
+ struct {
+ /*!< Reserved for future use */
+ } buffer;
+ } info;
+
+ unsigned int size_list;
+ char *auto_launch;
+ int pinup;
+ int timeout;
+ double period;
+ char *libexec;
+ } lb;
+
+ struct {
+ enum pd_type type;
+
+ union {
+ struct {
+ char *path;
+ char *group;
+ } script;
+
+ struct {
+ /*!< Reserved for future use */
+ } text;
+
+ struct {
+ /*!< Reserved for future use */
+ } buffer;
+ } info;
+
+ unsigned int width;
+ unsigned int height;
+ } pd;
+
+ int network;
+ int secured;
+ char *script; /* script type: edje, ... */
+ char *abi;
+
+ int fault_count;
+ struct fault_info *fault_info;
+
+ struct slave_node *slave;
+ int refcnt;
+
+ Eina_List *inst_list;
+ Eina_List *ctx_list;
+
+ int is_uninstalled;
+};
+
+static struct {
+ Eina_List *pkg_list;
+} s_info = {
+ .pkg_list = NULL,
+};
+
+static int slave_activated_cb(struct slave_node *slave, void *data)
+{
+ struct pkg_info *info = data;
+ struct inst_info *inst;
+ Eina_List *l;
+ Eina_List *n;
+ int cnt;
+ int ret;
+
+ if (!slave_need_to_reactivate_instances(slave)) {
+ DbgPrint("Do not need to reactivate instances\n");
+ return 0;
+ }
+
+ cnt = 0;
+ EINA_LIST_FOREACH_SAFE(info->inst_list, l, n, inst) {
+ ret = instance_recover_state(inst);
+ if (!ret)
+ continue;
+
+ instance_thaw_updator(inst);
+ cnt++;
+ }
+
+ DbgPrint("Recover state for %d instances of %s\n", cnt, package_name(info));
+ return 0;
+}
+
+static int slave_fault_cb(struct slave_node *slave, void *data)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct inst_info *inst;
+ struct pkg_info *info = (struct pkg_info *)data;
+
+ DbgPrint("Slave %s has critical fault. destroy all instances\n", slave_name(slave));
+ EINA_LIST_FOREACH_SAFE(info->inst_list, l, n, inst) {
+ DbgPrint("Destroy instance %p\n", inst);
+ instance_destroyed(inst);
+ }
+
+ return 0;
+}
+
+static int slave_deactivated_cb(struct slave_node *slave, void *data)
+{
+ struct pkg_info *info = data;
+ struct inst_info *inst;
+ Eina_List *l;
+ Eina_List *n;
+ int cnt = 0;
+
+ if (info->fault_info) {
+ EINA_LIST_FOREACH_SAFE(info->inst_list, l, n, inst) {
+ instance_destroyed(inst);
+ }
+ } else {
+ EINA_LIST_FOREACH_SAFE(info->inst_list, l, n, inst) {
+ cnt += instance_need_slave(inst);
+ /*!
+ * instance_deactivated will call the slave_unload_instance.
+ * if the loaded instance counter meets 0,
+ * the slave will be deactivated.
+ * so we should not call the instance activate function
+ * from here.
+ *
+ * activate slave when the slave is reactivated
+ */
+ }
+ }
+
+ return cnt ? SLAVE_NEED_TO_REACTIVATE : 0;
+}
+
+static int xmonitor_paused_cb(void *data)
+{
+ struct pkg_info *info = (struct pkg_info *)data;
+ struct inst_info *inst;
+ Eina_List *l;
+
+ if (slave_state(info->slave) != SLAVE_TERMINATED) {
+ DbgPrint("Skip this\n");
+ return 0;
+ }
+
+ EINA_LIST_FOREACH(info->inst_list, l, inst) {
+ instance_freeze_updator(inst);
+ }
+
+ return 0;
+}
+
+static int xmonitor_resumed_cb(void *data)
+{
+ struct pkg_info *info = data;
+ struct inst_info *inst;
+ Eina_List *l;
+
+ if (slave_state(info->slave) != SLAVE_TERMINATED) {
+ DbgPrint("Skip this\n");
+ return 0;
+ }
+
+ EINA_LIST_FOREACH(info->inst_list, l, inst) {
+ instance_thaw_updator(inst);
+ }
+
+ return 0;
+}
+
+static int slave_paused_cb(struct slave_node *slave, void *data)
+{
+ struct pkg_info *info = (struct pkg_info *)data;
+ struct inst_info *inst;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(info->inst_list, l, inst) {
+ instance_freeze_updator(inst);
+ }
+
+ return 0;
+}
+
+static int slave_resumed_cb(struct slave_node *slave, void *data)
+{
+ struct pkg_info *info = (struct pkg_info *)data;
+ struct inst_info *inst;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(info->inst_list, l, inst) {
+ instance_thaw_updator(inst);
+ }
+
+ return 0;
+}
+
+static inline void destroy_package(struct pkg_info *info)
+{
+ group_del_livebox(info->pkgname);
+ package_clear_fault(info);
+
+ s_info.pkg_list = eina_list_remove(s_info.pkg_list, info);
+
+ if (info->lb.type == LB_TYPE_SCRIPT) {
+ DbgFree(info->lb.info.script.path);
+ DbgFree(info->lb.info.script.group);
+ }
+
+ if (info->pd.type == PD_TYPE_SCRIPT) {
+ DbgFree(info->pd.info.script.path);
+ DbgFree(info->pd.info.script.group);
+ }
+
+ DbgFree(info->script);
+ DbgFree(info->abi);
+ DbgFree(info->pkgname);
+ DbgFree(info->lb.libexec);
+ DbgFree(info->lb.auto_launch);
+
+ DbgFree(info);
+}
+
+static inline int load_conf(struct pkg_info *info)
+{
+ struct parser *parser;
+ const char *str;
+ const char *group;
+
+ parser = parser_load(info->pkgname);
+ if (!parser) {
+ info->lb.size_list = 0x01; /* Default */
+
+ info->script = strdup(DEFAULT_SCRIPT);
+ if (!info->script) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ info->abi = strdup(DEFAULT_ABI);
+ if (!info->abi) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info->script);
+ info->script = NULL;
+ return -ENOMEM;
+ }
+
+ info->pd.width = g_conf.width;
+ info->pd.height = g_conf.height >> 2;
+ info->lb.pinup = 1;
+ return 0;
+ }
+
+ info->lb.type = LB_TYPE_FILE;
+ if (parser_text_lb(parser)) {
+ info->lb.type = LB_TYPE_TEXT;
+ } else if (parser_buffer_lb(parser)) {
+ info->lb.type = LB_TYPE_BUFFER;
+ } else {
+ str = parser_lb_path(parser);
+ if (str) {
+ info->lb.type = LB_TYPE_SCRIPT;
+
+ info->lb.info.script.path = strdup(str);
+ if (!info->lb.info.script.path) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ parser_unload(parser);
+ return -ENOMEM;
+ }
+
+ str = parser_lb_group(parser);
+ if (str) {
+ info->lb.info.script.group = strdup(str);
+ if (!info->lb.info.script.group) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info->lb.info.script.path);
+ parser_unload(parser);
+ return -ENOMEM;
+ }
+ }
+ }
+ }
+
+ if (parser_text_pd(parser)) {
+ info->pd.type = PD_TYPE_TEXT;
+ } else if (parser_buffer_pd(parser)) {
+ info->pd.type = PD_TYPE_BUFFER;
+ } else {
+ str = parser_pd_path(parser);
+ if (str) {
+ info->pd.type = PD_TYPE_SCRIPT;
+ info->pd.info.script.path = strdup(str);
+ if (!info->pd.info.script.path) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ if (info->lb.type == LB_TYPE_SCRIPT) {
+ DbgFree(info->lb.info.script.path);
+ DbgFree(info->lb.info.script.group);
+ }
+ parser_unload(parser);
+ return -ENOMEM;
+ }
+
+ str = parser_pd_group(parser);
+ if (str) {
+ info->pd.info.script.group = strdup(str);
+ if (!info->pd.info.script.group) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info->pd.info.script.path);
+ if (info->lb.type == LB_TYPE_SCRIPT) {
+ DbgFree(info->lb.info.script.path);
+ DbgFree(info->lb.info.script.group);
+ }
+ parser_unload(parser);
+ return -ENOMEM;
+ }
+ }
+ }
+ }
+
+ str = parser_script(parser);
+ str = str ? str : DEFAULT_SCRIPT;
+ info->script = strdup(str);
+ if (!info->script) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ if (info->pd.type == PD_TYPE_SCRIPT) {
+ DbgFree(info->pd.info.script.path);
+ DbgFree(info->pd.info.script.group);
+ }
+
+ if (info->lb.type == LB_TYPE_SCRIPT) {
+ DbgFree(info->lb.info.script.path);
+ DbgFree(info->lb.info.script.group);
+ }
+
+ parser_unload(parser);
+ return -ENOMEM;
+ }
+
+ str = parser_abi(parser);
+ str = str ? str : DEFAULT_ABI;
+ info->abi = strdup(str);
+ if (!info->abi) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info->script);
+ if (info->pd.type == PD_TYPE_SCRIPT) {
+ DbgFree(info->pd.info.script.path);
+ DbgFree(info->pd.info.script.group);
+ }
+
+ if (info->lb.type == LB_TYPE_SCRIPT) {
+ DbgFree(info->lb.info.script.path);
+ DbgFree(info->lb.info.script.group);
+ }
+ parser_unload(parser);
+ return -ENOMEM;
+ }
+
+ info->lb.timeout = parser_timeout(parser);
+ info->network = parser_network(parser);
+
+ info->lb.period = parser_period(parser);
+ if (info->lb.period < 0.0f)
+ info->lb.period = 0.0f;
+ else if (info->lb.period > 0.0f && info->lb.period < MINIMUM_PERIOD)
+ info->lb.period = MINIMUM_PERIOD;
+
+ info->lb.size_list = parser_size(parser);
+
+ str = parser_auto_launch(parser);
+ str = str ? str : "";
+ info->lb.auto_launch = strdup(str);
+ if (!info->lb.auto_launch) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info->abi);
+ DbgFree(info->script);
+ if (info->pd.type == PD_TYPE_SCRIPT) {
+ DbgFree(info->pd.info.script.path);
+ DbgFree(info->pd.info.script.group);
+ }
+
+ if (info->lb.type == LB_TYPE_SCRIPT) {
+ DbgFree(info->lb.info.script.path);
+ DbgFree(info->lb.info.script.group);
+ }
+ parser_unload(parser);
+ return -ENOMEM;
+ }
+
+ info->secured = parser_secured(parser);
+ info->lb.pinup = parser_pinup(parser);
+
+ parser_get_pdsize(parser, &info->pd.width, &info->pd.height);
+
+ group = parser_group_str(parser);
+ if (group && group_add_livebox(group, info->pkgname) < 0)
+ ErrPrint("Failed to build cluster tree for %s{%s}\n", info->pkgname, group);
+
+ parser_unload(parser);
+ return 0;
+}
+
+HAPI struct pkg_info *package_create(const char *pkgname)
+{
+ struct pkg_info *pkginfo;
+
+ pkginfo = calloc(1, sizeof(*pkginfo));
+ if (!pkginfo) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ pkginfo->pkgname = io_livebox_pkgname(pkgname);
+ if (!pkginfo->pkgname) {
+ ErrPrint("Failed to get pkgname, fallback to fs checker\n");
+ if (util_validate_livebox_package(pkgname) < 0) {
+ ErrPrint("Invalid package name: %s\n", pkgname);
+ DbgFree(pkginfo);
+ return NULL;
+ }
+
+ pkginfo->pkgname = strdup(pkgname);
+ if (!pkginfo->pkgname) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(pkginfo);
+ return NULL;
+ }
+ }
+
+ if (io_load_package_db(pkginfo) < 0) {
+ ErrPrint("Failed to load DB, fall back to conf file loader\n");
+ if (load_conf(pkginfo) < 0) {
+ ErrPrint("Failed to initiate the conf file loader\n");
+ DbgFree(pkginfo->pkgname);
+ DbgFree(pkginfo);
+ return NULL;
+ }
+ }
+
+ package_ref(pkginfo);
+
+ s_info.pkg_list = eina_list_append(s_info.pkg_list, pkginfo);
+
+ return pkginfo;
+}
+
+HAPI int package_destroy(struct pkg_info *info)
+{
+ package_unref(info);
+ return 0;
+}
+
+HAPI Eina_List *package_ctx_info(struct pkg_info *pkginfo)
+{
+ return pkginfo->ctx_list;
+}
+
+HAPI void package_add_ctx_info(struct pkg_info *pkginfo, struct context_info *info)
+{
+ pkginfo->ctx_list = eina_list_append(pkginfo->ctx_list, info);
+}
+
+HAPI char *package_lb_pkgname(const char *pkgname)
+{
+ char *lb_pkgname;
+
+ lb_pkgname = io_livebox_pkgname(pkgname);
+ if (!lb_pkgname) {
+ if (util_validate_livebox_package(pkgname) < 0)
+ return NULL;
+
+ lb_pkgname = strdup(pkgname);
+ if (!lb_pkgname) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+ }
+
+ return lb_pkgname;
+}
+
+HAPI int package_is_lb_pkgname(const char *pkgname)
+{
+ char *lb_pkgname;
+ int ret;
+
+ lb_pkgname = package_lb_pkgname(pkgname);
+ ret = !!lb_pkgname;
+ DbgFree(lb_pkgname);
+
+ return ret;
+}
+
+HAPI struct pkg_info *package_find(const char *pkgname)
+{
+ Eina_List *l;
+ struct pkg_info *info;
+
+ if (!pkgname)
+ return NULL;
+
+ EINA_LIST_FOREACH(s_info.pkg_list, l, info) {
+ if (!strcmp(info->pkgname, pkgname))
+ return info;
+ }
+
+ return NULL;
+}
+
+HAPI struct inst_info *package_find_instance_by_id(const char *pkgname, const char *id)
+{
+ Eina_List *l;
+ struct inst_info *inst;
+ struct pkg_info *info;
+
+ info = package_find(pkgname);
+ if (!info) {
+ ErrPrint("Package %s is not exists\n", pkgname);
+ return NULL;
+ }
+
+ EINA_LIST_FOREACH(info->inst_list, l, inst) {
+ if (!strcmp(instance_id(inst), id))
+ return inst;
+ }
+
+ return NULL;
+}
+
+HAPI struct inst_info *package_find_instance_by_timestamp(const char *pkgname, double timestamp)
+{
+ Eina_List *l;
+ struct inst_info *inst;
+ struct pkg_info *info;
+
+ info = package_find(pkgname);
+ if (!info) {
+ ErrPrint("Package %s is not exists\n", pkgname);
+ return NULL;
+ }
+
+ EINA_LIST_FOREACH(info->inst_list, l, inst) {
+ if (instance_timestamp(inst) == timestamp)
+ return inst;
+ }
+
+ return NULL;
+}
+
+HAPI int package_dump_fault_info(struct pkg_info *info)
+{
+ if (!info->fault_info)
+ return -ENOENT;
+
+ ErrPrint("=============\n");
+ ErrPrint("faulted at %lf\n", info->fault_info->timestamp);
+ ErrPrint("Package: %s\n", info->pkgname);
+ ErrPrint("Function: %s\n", info->fault_info->function);
+ ErrPrint("InstanceID: %s\n", info->fault_info->filename);
+ return 0;
+}
+
+HAPI int package_get_fault_info(struct pkg_info *info, double *timestamp, const char **filename, const char **function)
+{
+ if (!info->fault_info)
+ return -ENOENT;
+
+ *timestamp = info->fault_info->timestamp;
+ *filename = info->fault_info->filename;
+ *function = info->fault_info->function;
+ return 0;
+}
+
+HAPI int package_set_fault_info(struct pkg_info *info, double timestamp, const char *filename, const char *function)
+{
+ struct fault_info *fault;
+
+ package_clear_fault(info);
+
+ fault = calloc(1, sizeof(*fault));
+ if (!fault) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ fault->timestamp = timestamp;
+ if (!filename)
+ filename = "unknown";
+ if (!function)
+ function = "unknown";
+
+ fault->filename = strdup(filename);
+ if (!fault->filename) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(fault);
+ return -ENOMEM;
+ }
+
+ fault->function = strdup(function);
+ if (!fault->function) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(fault->filename);
+ DbgFree(fault);
+ return -ENOMEM;
+ }
+
+ info->fault_info = fault;
+ info->fault_count++;
+ return 0;
+}
+
+HAPI int package_clear_fault(struct pkg_info *info)
+{
+ if (!info->fault_info)
+ return -EINVAL;
+
+ package_dump_fault_info(info);
+
+ DbgFree(info->fault_info->function);
+ DbgFree(info->fault_info->filename);
+ DbgFree(info->fault_info);
+ info->fault_info = NULL;
+ return 0;
+}
+
+HAPI const int const package_is_fault(const struct pkg_info *info)
+{
+ return !!info->fault_info;
+}
+
+HAPI struct slave_node * const package_slave(const struct pkg_info *info)
+{
+ return info->slave;
+}
+
+HAPI const int const package_timeout(const struct pkg_info *info)
+{
+ return info->lb.timeout;
+}
+
+HAPI void package_set_timeout(struct pkg_info *info, int timeout)
+{
+ info->lb.timeout = timeout;
+}
+
+HAPI const double const package_period(const struct pkg_info *info)
+{
+ return info->lb.period;
+}
+
+HAPI void package_set_period(struct pkg_info *info, double period)
+{
+ info->lb.period = period;
+}
+
+HAPI const int const package_secured(const struct pkg_info *info)
+{
+ return info->secured;
+}
+
+HAPI void package_set_secured(struct pkg_info *info, int secured)
+{
+ info->secured = secured;
+}
+
+HAPI const char * const package_script(const struct pkg_info *info)
+{
+ return info->script;
+}
+
+HAPI int package_set_script(struct pkg_info *info, const char *script)
+{
+ char *tmp;
+
+ tmp = strdup(script);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ DbgFree(info->script);
+ info->script = tmp;
+ return 0;
+}
+
+HAPI const char * const package_abi(const struct pkg_info *info)
+{
+ return info->abi;
+}
+
+HAPI int package_set_abi(struct pkg_info *info, const char *abi)
+{
+ char *tmp;
+ tmp = strdup(abi);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ DbgFree(info->abi);
+ info->abi = tmp;
+ return 0;
+}
+
+HAPI const char * const package_lb_path(const struct pkg_info *info)
+{
+ if (info->lb.type != LB_TYPE_SCRIPT)
+ return NULL;
+
+ return info->lb.info.script.path;
+}
+
+HAPI int package_set_lb_path(struct pkg_info *info, const char *path)
+{
+ char *tmp;
+
+ if (info->lb.type != LB_TYPE_SCRIPT)
+ return -EINVAL;
+
+ tmp = strdup(path);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ DbgFree(info->lb.info.script.path);
+ info->lb.info.script.path = tmp;
+ return 0;
+}
+
+HAPI const char * const package_lb_group(const struct pkg_info *info)
+{
+ if (info->lb.type != LB_TYPE_SCRIPT)
+ return NULL;
+
+ return info->lb.info.script.group;
+}
+
+HAPI int package_set_lb_group(struct pkg_info *info, const char *group)
+{
+ char *tmp;
+
+ if (info->lb.type != LB_TYPE_SCRIPT)
+ return -EINVAL;
+
+ tmp = strdup(group);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ DbgFree(info->lb.info.script.group);
+ info->lb.info.script.group = tmp;
+ return 0;
+}
+
+HAPI const char * const package_pd_path(const struct pkg_info *info)
+{
+ if (info->pd.type != PD_TYPE_SCRIPT)
+ return NULL;
+
+ return info->pd.info.script.path;
+}
+
+HAPI int package_set_pd_path(struct pkg_info *info, const char *path)
+{
+ char *tmp;
+
+ if (info->pd.type != PD_TYPE_SCRIPT)
+ return -EINVAL;
+
+ tmp = strdup(path);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ DbgFree(info->pd.info.script.path);
+ info->pd.info.script.path = tmp;
+ return 0;
+}
+
+HAPI const char * const package_pd_group(const struct pkg_info *info)
+{
+ if (info->pd.type != PD_TYPE_SCRIPT)
+ return NULL;
+
+ return info->pd.info.script.group;
+}
+
+HAPI int package_set_pd_group(struct pkg_info *info, const char *group)
+{
+ char *tmp;
+
+ if (info->pd.type != PD_TYPE_SCRIPT)
+ return -EINVAL;
+
+ tmp = strdup(group);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ DbgFree(info->pd.info.script.group);
+ info->pd.info.script.group = tmp;
+ return 0;
+}
+
+HAPI const int const package_pinup(const struct pkg_info *info)
+{
+ return info->lb.pinup;
+}
+
+HAPI void package_set_pinup(struct pkg_info *info, int pinup)
+{
+ info->lb.pinup = pinup;
+}
+
+HAPI const char * const package_auto_launch(const struct pkg_info *info)
+{
+ return info->lb.auto_launch;
+}
+
+HAPI void package_set_auto_launch(struct pkg_info *info, const char *auto_launch)
+{
+ if (!auto_launch)
+ auto_launch = "";
+
+ info->lb.auto_launch = strdup(auto_launch);
+ if (!info->lb.auto_launch) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return;
+ }
+}
+
+HAPI const unsigned int const package_size_list(const struct pkg_info *info)
+{
+ return info->lb.size_list;
+}
+
+HAPI void package_set_size_list(struct pkg_info *info, unsigned int size_list)
+{
+ info->lb.size_list = size_list;
+}
+
+HAPI const int const package_pd_width(const struct pkg_info *info)
+{
+ return info->pd.width;
+}
+
+HAPI void package_set_pd_width(struct pkg_info *info, int width)
+{
+ info->pd.width = width;
+}
+
+HAPI const int const package_pd_height(const struct pkg_info *info)
+{
+ return info->pd.height;
+}
+
+HAPI void package_set_pd_height(struct pkg_info *info, int height)
+{
+ info->pd.height = height;
+}
+
+HAPI struct pkg_info * const package_ref(struct pkg_info *info)
+{
+ info->refcnt++;
+ return info;
+}
+
+HAPI struct pkg_info * const package_unref(struct pkg_info *info)
+{
+ if (info->refcnt == 0) {
+ ErrPrint("Invalid request\n");
+ return NULL;
+ }
+
+ info->refcnt--;
+ if (info->refcnt == 0) {
+ destroy_package(info);
+ info = NULL;
+ }
+
+ return info;
+}
+
+HAPI const int const package_refcnt(const struct pkg_info *info)
+{
+ return info->refcnt;
+}
+
+HAPI const enum lb_type package_lb_type(const struct pkg_info *info)
+{
+ return info->lb.type;
+}
+
+HAPI void package_set_lb_type(struct pkg_info *info, enum lb_type type)
+{
+ info->lb.type = type;
+}
+
+HAPI const char * const package_libexec(struct pkg_info *info)
+{
+ return info->lb.libexec;
+}
+
+HAPI int package_set_libexec(struct pkg_info *info, const char *libexec)
+{
+ char *tmp;
+
+ tmp = strdup(libexec);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ DbgFree(info->lb.libexec);
+ info->lb.libexec = tmp;
+ return 0;
+}
+
+HAPI int package_network(struct pkg_info *info)
+{
+ return info->network;
+}
+
+HAPI void package_set_network(struct pkg_info *info, int network)
+{
+ info->network = network;
+}
+
+HAPI const enum pd_type const package_pd_type(const struct pkg_info *info)
+{
+ return info->pd.type;
+}
+
+HAPI void package_set_pd_type(struct pkg_info *info, enum pd_type type)
+{
+ info->pd.type = type;
+}
+
+/*!
+ * \note
+ * Add the instance to the package info.
+ * If a package has no slave, assign a new slave.
+ */
+static inline int assign_new_slave(struct pkg_info *info)
+{
+ char *s_name;
+ char *s_pkgname;
+ const char *tmp;
+
+ s_name = util_slavename();
+ if (!s_name) {
+ ErrPrint("Failed to get a new slave name\n");
+ return -EFAULT;
+ }
+
+ tmp = abi_find_slave(info->abi);
+ if (!tmp) {
+ DbgFree(s_name);
+ ErrPrint("Failed to find a proper pkgname of a slave\n");
+ return -EINVAL;
+ }
+
+ DbgPrint("Slave package: \"%s\" (abi: %s)\n", tmp, info->abi);
+ s_pkgname = util_replace_string(tmp, REPLACE_TAG_APPID, info->pkgname);
+ if (!s_pkgname) {
+ DbgPrint("Failed to get replaced string\n");
+ s_pkgname = strdup(tmp);
+ if (!s_pkgname) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(s_name);
+ return -ENOMEM;
+ }
+ }
+
+ DbgPrint("New slave name is %s, it is assigned for livebox %s (using %s)\n", s_name, info->pkgname, s_pkgname);
+ info->slave = slave_create(s_name, info->secured, info->abi, s_pkgname);
+
+ DbgFree(s_name);
+ DbgFree(s_pkgname);
+
+ if (!info->slave) {
+ /*!
+ * \note
+ * package_destroy will try to remove "info" from the pkg_list.
+ * but we didn't add this to it yet.
+ * If the list method couldn't find an "info" from the list,
+ * it just do nothing so I'll leave this.
+ */
+ return -EFAULT;
+ }
+ /*!
+ * \note
+ * Slave is not activated yet.
+ */
+ return 0;
+}
+
+HAPI int package_add_instance(struct pkg_info *info, struct inst_info *inst)
+{
+ if (!info->inst_list) {
+ info->slave = slave_find_available(info->abi, info->secured);
+
+ if (!info->slave) {
+ int ret;
+
+ ret = assign_new_slave(info);
+ if (ret < 0)
+ return ret;
+ } else {
+ DbgPrint("Slave %s is assigned for %s\n", slave_name(info->slave), info->pkgname);
+ }
+
+ slave_ref(info->slave);
+ slave_load_package(info->slave);
+ slave_event_callback_add(info->slave, SLAVE_EVENT_DEACTIVATE, slave_deactivated_cb, info);
+ slave_event_callback_add(info->slave, SLAVE_EVENT_ACTIVATE, slave_activated_cb, info);
+ slave_event_callback_add(info->slave, SLAVE_EVENT_FAULT, slave_fault_cb, info);
+
+ if (info->secured) {
+ slave_event_callback_add(info->slave, SLAVE_EVENT_PAUSE, slave_paused_cb, info);
+ slave_event_callback_add(info->slave, SLAVE_EVENT_RESUME, slave_resumed_cb, info);
+
+ /*!
+ * \note
+ * In case of the slave is terminated because of expired TTL timer,
+ * Master should freeze the all update time.
+ * But the callback should check the slave's state to prevent from duplicated freezing.
+ *
+ * This callback will freeze the timer only if a slave doesn't running.
+ */
+ xmonitor_add_event_callback(XMONITOR_PAUSED, xmonitor_paused_cb, info);
+ xmonitor_add_event_callback(XMONITOR_RESUMED, xmonitor_resumed_cb, info);
+ }
+ }
+
+ info->inst_list = eina_list_append(info->inst_list, inst);
+ return 0;
+}
+
+HAPI int package_del_instance(struct pkg_info *info, struct inst_info *inst)
+{
+ info->inst_list = eina_list_remove(info->inst_list, inst);
+
+ if (info->inst_list)
+ return 0;
+
+ if (info->slave) {
+ slave_unload_package(info->slave);
+
+ slave_event_callback_del(info->slave, SLAVE_EVENT_FAULT, slave_fault_cb, info);
+ slave_event_callback_del(info->slave, SLAVE_EVENT_DEACTIVATE, slave_deactivated_cb, info);
+ slave_event_callback_del(info->slave, SLAVE_EVENT_ACTIVATE, slave_activated_cb, info);
+
+ if (info->secured) {
+ slave_event_callback_del(info->slave, SLAVE_EVENT_PAUSE, slave_paused_cb, info);
+ slave_event_callback_del(info->slave, SLAVE_EVENT_RESUME, slave_resumed_cb, info);
+
+ xmonitor_del_event_callback(XMONITOR_PAUSED, xmonitor_paused_cb, info);
+ xmonitor_del_event_callback(XMONITOR_RESUMED, xmonitor_resumed_cb, info);
+ }
+
+ slave_unref(info->slave);
+ info->slave = NULL;
+ }
+
+ if (info->is_uninstalled)
+ package_destroy(info);
+
+ return 0;
+}
+
+HAPI Eina_List *package_instance_list(struct pkg_info *info)
+{
+ return info->inst_list;
+}
+
+static int client_created_cb(struct client_node *client, void *data)
+{
+ struct pkg_info *info;
+ Eina_List *l;
+
+ struct inst_info *inst;
+ Eina_List *i_l;
+
+ EINA_LIST_FOREACH(s_info.pkg_list, l, info) {
+ if (info->fault_info) {
+ fault_unicast_info(client, info->pkgname, info->fault_info->filename, info->fault_info->function);
+ continue;
+ }
+
+ EINA_LIST_FOREACH(info->inst_list, i_l, inst) {
+ switch (instance_state(inst)) {
+ case INST_INIT:
+ /* Will be send a created event after the instance gets created event */
+ break;
+ case INST_ACTIVATED: /*!< This instance is actiavted, and used */
+ case INST_REQUEST_TO_REACTIVATE: /*!< This instance will be reactivated soon */
+ case INST_REQUEST_TO_DESTROY: /*!< This instance will be destroy soon */
+ if (instance_client(inst) == client) {
+ instance_unicast_created_event(inst, client);
+ } else if (instance_client(inst) == NULL) {
+ /*!
+ * \note
+ * Instances are lives in the system cluster/sub-cluster
+ */
+ if (client_is_subscribed(client, instance_cluster(inst), instance_category(inst))) {
+ instance_unicast_created_event(inst, client);
+ DbgPrint("(Subscribed) Created package: %s\n", info->pkgname);
+ }
+ }
+
+ break;
+ default:
+ DbgPrint("%s(%s) is not activated (%d)\n",
+ package_name(info), instance_id(inst), instance_state(inst));
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int io_uninstall_cb(const char *pkgname, int prime, void *data)
+{
+ struct pkg_info *info;
+ Eina_List *l;
+ Eina_List *n;
+ struct inst_info *inst;
+
+ DbgPrint("Livebox package %s is uninstalled\n", pkgname);
+ info = package_find(pkgname);
+ if (!info) {
+ DbgPrint("%s is not yet loaded\n", pkgname);
+ return 0;
+ }
+
+ info->is_uninstalled = 1;
+
+ /*!
+ * \NOTE
+ * Don't delete an item from the inst_list.
+ * destroy callback will use this list again.
+ * So, Don't touch it from here.
+ */
+ if (info->inst_list) {
+ EINA_LIST_FOREACH_SAFE(info->inst_list, l, n, inst) {
+ instance_destroy(inst);
+ }
+ } else {
+ package_destroy(info);
+ }
+
+ return 0;
+}
+
+static inline void reload_package_info(struct pkg_info *info)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct inst_info *inst;
+
+ DbgPrint("Already exists, try to update it\n");
+ /*!
+ * \note
+ * Without "is_uninstalled", the package will be kept
+ */
+ EINA_LIST_FOREACH_SAFE(info->inst_list, l, n, inst) {
+ instance_destroy(inst);
+ }
+
+ group_del_livebox(info->pkgname);
+ package_clear_fault(info);
+
+ /*!
+ * \NOTE:
+ * Nested DB I/O
+ */
+ io_load_package_db(info);
+}
+
+static int io_install_cb(const char *pkgname, int prime, void *data)
+{
+ struct pkg_info *info;
+
+ DbgPrint("Livebox package %s is installed\n", pkgname);
+ info = package_find(pkgname);
+ if (info) {
+ reload_package_info(info);
+ } else {
+ info = package_create(pkgname);
+ DbgPrint("Package %s is%sbuilt\n", pkgname, info ? " " : " not ");
+ }
+
+ return 0;
+}
+
+static int install_cb(const char *pkgname, enum pkgmgr_status status, double value, void *data)
+{
+ int ret;
+
+ if (status != PKGMGR_STATUS_END)
+ return 0;
+
+ ret = io_update_livebox_package(pkgname, io_install_cb, NULL);
+ DbgPrint("Processed %d packages\n", ret);
+ return 0;
+}
+
+static int uninstall_cb(const char *pkgname, enum pkgmgr_status status, double value, void *data)
+{
+ int ret;
+
+ if (status == PKGMGR_STATUS_START) {
+ ret = io_update_livebox_package(pkgname, io_uninstall_cb, NULL);
+ DbgPrint("Processed %d packages\n", ret);
+ if (ret == 0) {
+ /*! for keeping the old style */
+ (void)io_uninstall_cb(pkgname, -1, NULL);
+ }
+ }
+
+ return 0;
+}
+
+static int io_update_cb(const char *pkgname, int prime, void *data)
+{
+ struct pkg_info *info;
+
+ DbgPrint("Livebox package %s is updated\n", pkgname);
+ info = package_find(pkgname);
+ if (!info)
+ return 0;
+
+ reload_package_info(info);
+ return 0;
+}
+
+static int update_cb(const char *pkgname, enum pkgmgr_status status, double value, void *data)
+{
+ int ret;
+ if (status != PKGMGR_STATUS_END)
+ return 0;
+
+ ret = io_update_livebox_package(pkgname, io_update_cb, NULL);
+ DbgPrint("Processed %d packages\n", ret);
+ return 0;
+}
+
+static int crawling_liveboxes(const char *pkgname, int prime, void *data)
+{
+ if (package_find(pkgname)) {
+ ErrPrint("Information of %s is already built\n", pkgname);
+ } else {
+ struct pkg_info *info;
+ info = package_create(pkgname);
+ if (info)
+ DbgPrint("[%s] information is built prime(%d)\n", pkgname, prime);
+ }
+
+ return 0;
+}
+
+HAPI int package_init(void)
+{
+ client_global_event_handler_add(CLIENT_GLOBAL_EVENT_CREATE, client_created_cb, NULL);
+ pkgmgr_init();
+
+ pkgmgr_add_event_callback(PKGMGR_EVENT_INSTALL, install_cb, NULL);
+ pkgmgr_add_event_callback(PKGMGR_EVENT_UNINSTALL, uninstall_cb, NULL);
+ pkgmgr_add_event_callback(PKGMGR_EVENT_UPDATE, update_cb, NULL);
+
+ io_crawling_liveboxes(crawling_liveboxes, NULL);
+ return 0;
+}
+
+HAPI int package_fini(void)
+{
+ pkgmgr_del_event_callback(PKGMGR_EVENT_INSTALL, install_cb, NULL);
+ pkgmgr_del_event_callback(PKGMGR_EVENT_UNINSTALL, uninstall_cb, NULL);
+ pkgmgr_del_event_callback(PKGMGR_EVENT_UPDATE, update_cb, NULL);
+ pkgmgr_fini();
+ client_global_event_handler_del(CLIENT_GLOBAL_EVENT_CREATE, client_created_cb, NULL);
+ return 0;
+}
+
+HAPI const char *package_find_by_secured_slave(struct slave_node *slave)
+{
+ Eina_List *l;
+ struct pkg_info *info;
+
+ if (!slave_is_secured(slave))
+ return NULL;
+
+ EINA_LIST_FOREACH(s_info.pkg_list, l, info) {
+ if (info->slave == slave)
+ return info->pkgname;
+ }
+
+ return NULL;
+}
+
+HAPI const char * const package_name(const struct pkg_info *info)
+{
+ return info->pkgname;
+}
+
+/*!
+ * del_or_creat : 1 == create, 0 == delete
+ */
+HAPI int package_alter_instances_to_client(struct client_node *client, enum alter_type alter)
+{
+ struct pkg_info *info;
+ Eina_List *l;
+
+ struct inst_info *inst;
+ Eina_List *i_l;
+
+ EINA_LIST_FOREACH(s_info.pkg_list, l, info) {
+ EINA_LIST_FOREACH(info->inst_list, i_l, inst) {
+ if (instance_client(inst))
+ continue;
+
+ if (!client_is_subscribed(client, instance_cluster(inst), instance_category(inst)))
+ continue;
+
+ switch (instance_state(inst)) {
+ case INST_INIT:
+ case INST_REQUEST_TO_ACTIVATE:
+ /* Will be send a created event after the instance gets created event */
+ switch (alter) {
+ case ALTER_CREATE:
+ if (!instance_has_client(inst, client)) {
+ instance_add_client(inst, client);
+ }
+ break;
+ case ALTER_DESTROY:
+ if (instance_has_client(inst, client)) {
+ instance_del_client(inst, client);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case INST_ACTIVATED: /*!< This instance is actiavted, and used */
+ case INST_REQUEST_TO_REACTIVATE: /*!< This instance will be reactivated soon */
+ case INST_REQUEST_TO_DESTROY: /*!< This instance will be destroy soon */
+ /*!
+ * \note
+ * Instances are lives in the system cluster/sub-cluster
+ */
+ switch (alter) {
+ case ALTER_CREATE:
+ if (!instance_has_client(inst, client)) {
+ instance_unicast_created_event(inst, client);
+ instance_add_client(inst, client);
+ DbgPrint("(Subscribed) Created package: %s\n", info->pkgname);
+ }
+ break;
+ case ALTER_DESTROY:
+ if (instance_has_client(inst, client)) {
+ instance_unicast_deleted_event(inst, client);
+ instance_del_client(inst, client);
+ }
+ break;
+ default:
+ break;
+ }
+
+ break;
+ default:
+ DbgPrint("%s(%s) is not activated (%d)\n",
+ package_name(info), instance_id(inst), instance_state(inst));
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+HAPI const Eina_List *package_list(void)
+{
+ return s_info.pkg_list;
+}
+
+HAPI int const package_fault_count(struct pkg_info *info)
+{
+ return info ? info->fault_count : 0;
+}
+
+/* End of a file */
diff --git a/src/parser.c b/src/parser.c
new file mode 100644
index 0000000..871a6ff
--- /dev/null
+++ b/src/parser.c
@@ -0,0 +1,845 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h> /* strtod */
+#include <errno.h>
+#include <ctype.h> /* isspace */
+
+#include <Eina.h>
+#include <dlog.h>
+
+#include <livebox-service.h>
+
+#include "util.h"
+#include "debug.h"
+#include "conf.h"
+#include "parser.h"
+
+static Eina_List *s_list;
+int errno;
+
+struct parser {
+ char *filename;
+ double period;
+ int timeout;
+ int network;
+ char *auto_launch;
+ unsigned int size;
+ unsigned int pd_width;
+ unsigned int pd_height;
+ char *group;
+ int secured;
+
+ char *pd_path;
+ char *pd_group;
+
+ char *lb_path;
+ char *lb_group;
+ int pinup;
+ int text_pd;
+ int text_lb;
+ int buffer_pd;
+ int buffer_lb;
+
+ char *abi;
+
+ char *script;
+};
+
+HAPI double parser_period(struct parser *handle)
+{
+ return handle->period;
+}
+
+HAPI int parser_network(struct parser *handle)
+{
+ return handle->network;
+}
+
+HAPI int parser_timeout(struct parser *handle)
+{
+ return handle->timeout;
+}
+
+HAPI const char *parser_auto_launch(struct parser *handle)
+{
+ return handle->auto_launch;
+}
+
+HAPI const char *parser_script(struct parser *handle)
+{
+ return handle->script;
+}
+
+HAPI const char *parser_abi(struct parser *handle)
+{
+ return handle->abi;
+}
+
+HAPI unsigned int parser_size(struct parser *handle)
+{
+ return handle->size;
+}
+
+HAPI const char *parser_lb_path(struct parser *handle)
+{
+ return handle->lb_path;
+}
+
+HAPI const char *parser_lb_group(struct parser *handle)
+{
+ return handle->lb_group;
+}
+
+HAPI const char *parser_pd_path(struct parser *handle)
+{
+ return handle->pd_path;
+}
+
+HAPI const char *parser_pd_group(struct parser *handle)
+{
+ return handle->pd_group;
+}
+
+HAPI const char *parser_group_str(struct parser *handle)
+{
+ return handle->group;
+}
+
+HAPI int parser_secured(struct parser *handle)
+{
+ return handle->secured;
+}
+
+HAPI void parser_get_pdsize(struct parser *handle, unsigned int *width, unsigned int *height)
+{
+ *width = handle->pd_width;
+ *height = handle->pd_height;
+}
+
+HAPI int parser_pinup(struct parser *handle)
+{
+ return handle->pinup;
+}
+
+HAPI int parser_text_lb(struct parser *handle)
+{
+ return handle->text_lb;
+}
+
+HAPI int parser_text_pd(struct parser *handle)
+{
+ return handle->text_pd;
+}
+
+HAPI int parser_buffer_lb(struct parser *handle)
+{
+ return handle->buffer_lb;
+}
+
+HAPI int parser_buffer_pd(struct parser *handle)
+{
+ return handle->buffer_pd;
+}
+
+HAPI int parser_find(const char *pkgname)
+{
+ Eina_List *l;
+ struct parser *item;
+ char *filename;
+ int len;
+ int ret;
+
+ len = strlen(pkgname) * 2 + strlen(CONF_PATH);
+
+ filename = malloc(len);
+ if (!filename)
+ return 0;
+
+ ret = snprintf(filename, len, CONF_PATH, pkgname, pkgname);
+ if (ret < 0) {
+ DbgFree(filename);
+ return -EFAULT;
+ }
+
+ DbgPrint("Conf file is %s for package %s\n", filename, pkgname);
+
+ EINA_LIST_FOREACH(s_list, l, item) {
+ if (!strcmp(item->filename, filename)) {
+ DbgFree(filename);
+ return (int)item;
+ }
+ }
+
+ DbgFree(filename);
+ return 0;
+}
+
+static inline int parse_size(const char *buffer, unsigned int *size)
+{
+ register int i;
+ int w;
+ int h;
+
+ enum {
+ START,
+ WIDTH,
+ DELIM,
+ HEIGHT,
+ ERROR,
+ STOP,
+ END,
+ } state;
+
+ *size = 0;
+ state = START;
+ i = 0;
+ w = 0;
+ h = 0;
+
+ while (state != ERROR && state != END) {
+ switch (state) {
+ case START:
+ switch (buffer[i]) {
+ case '1'...'9':
+ state = WIDTH;
+ break;
+ case ' ':
+ case '\t':
+ case ';':
+ i++;
+ break;
+ case '\0':
+ state = END;
+ break;
+ default:
+ state = ERROR;
+ break;
+ }
+ break;
+ case WIDTH:
+ switch (buffer[i]) {
+ case '0'...'9':
+ w = (w * 10) + (buffer[i] - '0');
+ i++;
+ break;
+ case 'x':
+ state = DELIM;
+ i++;
+ break;
+ default:
+ state = ERROR;
+ break;
+ }
+
+ break;
+ case DELIM:
+ switch (buffer[i]) {
+ case '1'...'9':
+ state = HEIGHT;
+ break;
+ case ' ':
+ case '\t':
+ i++;
+ break;
+ default:
+ state = ERROR;
+ break;
+ }
+ break;
+ case HEIGHT:
+ switch (buffer[i]) {
+ case '0'...'9':
+ h = (h * 10) + (buffer[i] - '0');
+ i++;
+ break;
+ case ';':
+ case '\0':
+ state = STOP;
+ break;
+ default:
+ state = ERROR;
+ break;
+ }
+ break;
+ case STOP:
+ if (w == 1 && h == 1) {
+ *size |= LB_SIZE_TYPE_1x1;
+ } else if (w == 2 && h == 1) {
+ *size |= LB_SIZE_TYPE_2x1;
+ } else if (w == 2 && h == 2) {
+ *size |= LB_SIZE_TYPE_2x2;
+ } else if (w == 4 && h == 1) {
+ *size |= LB_SIZE_TYPE_4x1;
+ } else if (w == 4 && h == 2) {
+ *size |= LB_SIZE_TYPE_4x2;
+ } else if (w == 4 && h == 3) {
+ *size |= LB_SIZE_TYPE_4x3;
+ } else if (w == 4 && h == 4) {
+ *size |= LB_SIZE_TYPE_4x4;
+ } else if (w == 21 && h == 21) {
+ *size |= LB_SIZE_TYPE_EASY_1x1;
+ } else if (w == 23 && h == 21) {
+ *size |= LB_SIZE_TYPE_EASY_3x1;
+ } else if (w == 23 && h == 23) {
+ *size |= LB_SIZE_TYPE_EASY_3x3;
+ } else {
+ ErrPrint("Invalid size type: %dx%d\n", w, h);
+ }
+
+ if (buffer[i] == ';')
+ state = START;
+ else if (buffer[i] == '\0')
+ state = END;
+
+ w = 0;
+ h = 0;
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ return *size ? 0 : -1;
+}
+
+/*!
+ * \note
+ * This will change the value of "buffer"
+ */
+static inline const char *rtrim(char *buffer)
+{
+ int len;
+
+ len = strlen(buffer);
+ while (len > 0 && isspace(buffer[len - 1]))
+ len--;
+
+ if (len <= 0)
+ return NULL;
+
+ buffer[len] = '\0';
+
+ return buffer;
+}
+
+/*!
+ * \note
+ * This will change the value of "buffer"
+ */
+static inline char *dup_rtrim(char *buffer)
+{
+ char *ret;
+
+ if (!rtrim(buffer))
+ return NULL;
+
+ ret = strdup(buffer);
+ if (!ret) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ return ret;
+}
+
+static void period_handler(struct parser *item, char *buffer)
+{
+ char *tmp = NULL;
+
+ if (!rtrim(buffer))
+ return;
+
+ item->period = strtod(buffer, &tmp);
+}
+
+static void timeout_handler(struct parser *item, char *buffer)
+{
+ if (!rtrim(buffer))
+ return;
+
+ item->timeout = atoi(buffer);
+}
+
+static void network_handler(struct parser *item, char *buffer)
+{
+ if (!rtrim(buffer))
+ return;
+
+ item->network = !!atoi(buffer);
+}
+
+static void auto_launch_handler(struct parser *item, char *buffer)
+{
+ if (!rtrim(buffer))
+ return;
+
+ item->auto_launch = strdup(buffer);
+ if (!item->auto_launch) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return;
+ }
+}
+
+static void size_handler(struct parser *item, char *buffer)
+{
+ if (parse_size(buffer, &item->size) == -1) {
+ ErrPrint("Failed to get size\n");
+ item->size = 0x00000001;
+ }
+}
+
+static void pd_size_handler(struct parser *item, char *buffer)
+{
+ if (sscanf(buffer, "%ux%u", &item->pd_width, &item->pd_height) != 2)
+ ErrPrint("parse pd size\n");
+}
+
+static void text_lb_handler(struct parser *item, char *buffer)
+{
+ if (!rtrim(buffer))
+ return;
+
+ item->text_lb = !!atoi(buffer);
+}
+
+static void abi_handler(struct parser *item, char *buffer)
+{
+ item->abi = dup_rtrim(buffer);
+}
+
+static void script_handler(struct parser *item, char *buffer)
+{
+ item->script = dup_rtrim(buffer);
+}
+
+static void buffer_pd_handler(struct parser *item, char *buffer)
+{
+ if (!rtrim(buffer))
+ return;
+
+ item->buffer_pd = !!atoi(buffer);
+}
+
+static void buffer_lb_handler(struct parser *item, char *buffer)
+{
+ if (!rtrim(buffer))
+ return;
+ item->buffer_lb = !!atoi(buffer);
+}
+
+static void text_pd_handler(struct parser *item, char *buffer)
+{
+ if (!rtrim(buffer))
+ return;
+
+ item->text_pd = !!atoi(buffer);
+}
+
+static void pinup_handler(struct parser *item, char *buffer)
+{
+ if (!rtrim(buffer))
+ return;
+
+ item->pinup = !!atoi(buffer);
+}
+
+static void lb_path_handler(struct parser *item, char *buffer)
+{
+ if (item->lb_path)
+ DbgFree(item->lb_path);
+
+ item->lb_path = dup_rtrim(buffer);
+ if (!item->lb_path)
+ ErrPrint("Error: %s\n", strerror(errno));
+}
+
+static void group_handler(struct parser *item, char *buffer)
+{
+ if (item->group)
+ DbgFree(item->group);
+
+ item->group = dup_rtrim(buffer);
+ if (!item->group)
+ ErrPrint("Error: %s\n", strerror(errno));
+}
+
+static void secured_handler(struct parser *item, char *buffer)
+{
+ if (!rtrim(buffer))
+ return;
+
+ item->secured = !!atoi(buffer);
+}
+
+static void lb_group_handler(struct parser *item, char *buffer)
+{
+ if (item->lb_group)
+ DbgFree(item->lb_group);
+
+ item->lb_group = dup_rtrim(buffer);
+ if (!item->lb_group)
+ ErrPrint("Error: %s\n", strerror(errno));
+}
+
+static void pd_path_handler(struct parser *item, char *buffer)
+{
+ if (item->pd_path)
+ DbgFree(item->pd_path);
+
+ item->pd_path = dup_rtrim(buffer);
+ if (!item->pd_path)
+ ErrPrint("Error: %s\n", strerror(errno));
+}
+
+static void pd_group_handler(struct parser *item, char *buffer)
+{
+ if (item->pd_group)
+ DbgFree(item->pd_group);
+
+ item->pd_group = dup_rtrim(buffer);
+ if (!item->pd_group)
+ ErrPrint("Error: %s\n", strerror(errno));
+}
+
+HAPI struct parser *parser_load(const char *pkgname)
+{
+ struct parser *item;
+ 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 len;
+ int linelen;
+ char buffer[256];
+ static const struct token_parser {
+ const char *name;
+ void (*handler)(struct parser *, char *buffer);
+ } token_handler[] = {
+ {
+ .name = "period",
+ .handler = period_handler,
+ },
+ {
+ .name = "timeout",
+ .handler = timeout_handler,
+ },
+ {
+ .name = "network",
+ .handler = network_handler,
+ },
+ {
+ .name = "auto_launch",
+ .handler = auto_launch_handler,
+ },
+ {
+ .name = "size",
+ .handler = size_handler,
+ },
+ {
+ .name = "group",
+ .handler = group_handler,
+ },
+ {
+ .name = "secured",
+ .handler = secured_handler,
+ },
+ {
+ .name = "livebox_path",
+ .handler = lb_path_handler,
+ },
+ {
+ .name = "livebox_group",
+ .handler = lb_group_handler,
+ },
+ {
+ .name = "pd_path",
+ .handler = pd_path_handler,
+ },
+ {
+ .name = "pd_group",
+ .handler = pd_group_handler,
+ },
+ {
+ .name = "pd_size",
+ .handler = pd_size_handler,
+ },
+ {
+ .name = "pinup",
+ .handler = pinup_handler,
+ },
+ {
+ .name = "text_livebox",
+ .handler = text_lb_handler,
+ },
+ {
+ .name = "text_pd",
+ .handler = text_pd_handler,
+ },
+ {
+ .name = "buffer_livebox",
+ .handler = buffer_lb_handler,
+ },
+ {
+ .name = "buffer_pd",
+ .handler = buffer_pd_handler,
+ },
+ {
+ .name = "script",
+ .handler = script_handler,
+ },
+ {
+ .name = "abi",
+ .handler = abi_handler,
+ },
+ {
+ .name = NULL,
+ .handler = NULL,
+ },
+ };
+ int ret;
+
+ item = calloc(1, sizeof(*item));
+ if (!item)
+ return 0;
+
+ /* live-, .conf */
+ len = strlen(CONF_PATH) + strlen(pkgname) * 2;
+ item->filename = malloc(len);
+ if (!item->filename) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ DbgFree(item);
+ return 0;
+ }
+
+ ret = snprintf(item->filename, len, CONF_PATH, pkgname, pkgname);
+ if (ret < 0) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ DbgFree(item->filename);
+ DbgFree(item);
+ return 0;
+ }
+
+ item->lb_path = NULL;
+ item->lb_group = NULL;
+ item->pd_width = 0;
+ item->pd_height = 0;
+ item->auto_launch = NULL;
+ item->size = 0x00000001;
+ item->group = NULL;
+ item->secured = 0;
+ item->pinup = 0;
+
+ fp = fopen(item->filename, "rt");
+ if (!fp) {
+ DbgFree(item->filename);
+ DbgFree(item);
+ return 0;
+ }
+
+ 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;
+
+ /*!
+ * \NOTE
+ * Make the string terminator
+ */
+ buffer[buffer_idx] = '\0';
+
+ if (token_idx >= 0 && token_handler[token_idx].handler)
+ token_handler[token_idx].handler(item, 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);
+
+ fclose(fp);
+
+ s_list = eina_list_append(s_list, item);
+ return item;
+}
+
+HAPI int parser_unload(struct parser *item)
+{
+ s_list = eina_list_remove(s_list, item);
+
+ DbgFree(item->auto_launch);
+ DbgFree(item->abi);
+ DbgFree(item->script);
+ DbgFree(item->group);
+ DbgFree(item->pd_group);
+ DbgFree(item->pd_path);
+ DbgFree(item->lb_group);
+ DbgFree(item->lb_path);
+ DbgFree(item->filename);
+ DbgFree(item);
+ return 0;
+}
+
+/* End of a file */
diff --git a/src/pkgmgr.c b/src/pkgmgr.c
new file mode 100644
index 0000000..72693d7
--- /dev/null
+++ b/src/pkgmgr.c
@@ -0,0 +1,602 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <dlog.h>
+#include <package-manager.h>
+
+#include <Ecore.h>
+#include "util.h"
+#include "debug.h"
+#include "pkgmgr.h"
+#include "conf.h"
+
+struct item {
+ char *pkgname;
+ char *icon;
+
+ enum pkgmgr_event_type type;
+ enum pkgmgr_status status;
+};
+
+static struct {
+ pkgmgr_client *listen_pc;
+ Eina_List *item_list;
+
+ Eina_List *install_event;
+ Eina_List *uninstall_event;
+ Eina_List *update_event;
+ Eina_List *download_event;
+ Eina_List *recover_event;
+} s_info = {
+ .listen_pc = NULL,
+ .item_list = NULL,
+
+ .install_event = NULL,
+ .uninstall_event = NULL,
+ .update_event = NULL,
+ .download_event = NULL,
+ .recover_event = NULL,
+};
+
+struct event_item {
+ int (*cb)(const char *pkgname, enum pkgmgr_status status, double value, void *data);
+ void *data;
+};
+
+static inline void invoke_install_event_handler(const char *pkgname, enum pkgmgr_status status, double value)
+{
+ Eina_List *l;
+ struct event_item *item;
+
+ EINA_LIST_FOREACH(s_info.install_event, l, item) {
+ if (item->cb)
+ item->cb(pkgname, status, value, item->data);
+ }
+}
+
+static inline void invoke_uninstall_event_handler(const char *pkgname, enum pkgmgr_status status, double value)
+{
+ Eina_List *l;
+ struct event_item *item;
+
+ EINA_LIST_FOREACH(s_info.uninstall_event, l, item) {
+ if (item->cb)
+ item->cb(pkgname, status, value, item->data);
+ }
+}
+
+static inline void invoke_update_event_handler(const char *pkgname, enum pkgmgr_status status, double value)
+{
+ Eina_List *l;
+ struct event_item *item;
+
+ EINA_LIST_FOREACH(s_info.update_event, l, item) {
+ if (item->cb)
+ item->cb(pkgname, status, value, item->data);
+ }
+}
+
+static inline void invoke_download_event_handler(const char *pkgname, enum pkgmgr_status status, double value)
+{
+ Eina_List *l;
+ struct event_item *item;
+
+ EINA_LIST_FOREACH(s_info.download_event, l, item) {
+ if (item->cb)
+ item->cb(pkgname, status, value, item->data);
+ }
+}
+
+static inline void invoke_recover_event_handler(const char *pkgname, enum pkgmgr_status status, double value)
+{
+ Eina_List *l;
+ struct event_item *item;
+
+ EINA_LIST_FOREACH(s_info.recover_event, l, item) {
+ if (item->cb)
+ item->cb(pkgname, status, value, item->data);
+ }
+}
+
+static inline void invoke_callback(const char *pkgname, struct item *item, double value)
+{
+ switch (item->type) {
+ case PKGMGR_EVENT_DOWNLOAD:
+ invoke_download_event_handler(pkgname, item->status, value);
+ break;
+ case PKGMGR_EVENT_UNINSTALL:
+ invoke_uninstall_event_handler(pkgname, item->status, value);
+ break;
+ case PKGMGR_EVENT_INSTALL:
+ invoke_install_event_handler(pkgname, item->status, value);
+ break;
+ case PKGMGR_EVENT_UPDATE:
+ invoke_update_event_handler(pkgname, item->status, value);
+ break;
+ case PKGMGR_EVENT_RECOVER:
+ invoke_recover_event_handler(pkgname, item->status, value);
+ break;
+ default:
+ ErrPrint("Unknown type: %d\n", item->type);
+ break;
+ }
+}
+
+static inline int is_valid_status(struct item *item, const char *status)
+{
+ const char *expected_status;
+
+ switch (item->type) {
+ case PKGMGR_EVENT_DOWNLOAD:
+ expected_status = "download";
+ break;
+ case PKGMGR_EVENT_UNINSTALL:
+ expected_status = "uninstall";
+ break;
+ case PKGMGR_EVENT_INSTALL:
+ expected_status = "install";
+ break;
+ case PKGMGR_EVENT_UPDATE:
+ expected_status = "update";
+ break;
+ case PKGMGR_EVENT_RECOVER:
+ expected_status = "recover";
+ break;
+ default:
+ return 0;
+ }
+
+ return !strcasecmp(status, expected_status);
+}
+
+static struct item *find_item(const char *pkgname)
+{
+ Eina_List *l;
+ struct item *item;
+
+ if (!pkgname) {
+ ErrPrint("Package name is not valid\n");
+ return NULL;
+ }
+
+ EINA_LIST_FOREACH(s_info.item_list, l, item) {
+ if (strcmp(item->pkgname, pkgname))
+ continue;
+
+ return item;
+ }
+
+ DbgPrint("Package %s is not found\n", pkgname);
+ return NULL;
+}
+
+static int start_cb(const char *pkgname, const char *val, void *data)
+{
+ struct item *item;
+
+ DbgPrint("[%s] %s\n", pkgname, val);
+
+ item = calloc(1, sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ item->pkgname = strdup(pkgname);
+ if (!item->pkgname) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item);
+ return -ENOMEM;
+ }
+
+ item->status = PKGMGR_STATUS_START;
+ s_info.item_list = eina_list_append(s_info.item_list, item);
+
+ if (!strcasecmp(val, "download")) {
+ item->type = PKGMGR_EVENT_DOWNLOAD;
+ } else if (!strcasecmp(val, "uninstall")) {
+ item->type = PKGMGR_EVENT_UNINSTALL;
+ } else if (!strcasecmp(val, "install")) {
+ item->type = PKGMGR_EVENT_INSTALL;
+ } else if (!strcasecmp(val, "update")) {
+ item->type = PKGMGR_EVENT_UPDATE;
+ } else if (!strcasecmp(val, "recover")) {
+ item->type = PKGMGR_EVENT_RECOVER;
+ } else {
+ DbgFree(item->pkgname);
+ DbgFree(item);
+ ErrPrint("Invalid val: %s\n", val);
+ return -EINVAL;
+ }
+
+ invoke_callback(pkgname, item, 0.0f);
+ return 0;
+}
+
+static int icon_path_cb(const char *pkgname, const char *val, void *data)
+{
+ struct item *item;
+
+ DbgPrint("[%s] %s\n", pkgname, val);
+
+ item = find_item(pkgname);
+ if (!item)
+ return -ENOENT;
+
+ if (item->icon)
+ DbgFree(item->icon);
+
+ item->icon = strdup(val);
+ if (!item->icon) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int command_cb(const char *pkgname, const char *val, void *data)
+{
+ struct item *item;
+
+ DbgPrint("[%s] %s\n", pkgname, val);
+
+ item = find_item(pkgname);
+ if (!item)
+ return -ENOENT;
+
+ if (!is_valid_status(item, val)) {
+ DbgPrint("Invalid status: %d, %s\n", item->type, val);
+ return -EINVAL;
+ }
+
+ item->status = PKGMGR_STATUS_COMMAND;
+ invoke_callback(pkgname, item, 0.0f);
+ return 0;
+}
+
+static int error_cb(const char *pkgname, const char *val, void *data)
+{
+ /* val = error */
+ struct item *item;
+
+ DbgPrint("[%s] %s\n", pkgname, val);
+
+ item = find_item(pkgname);
+ if (!item)
+ return -ENOENT;
+
+ item->status = PKGMGR_STATUS_ERROR;
+ invoke_callback(pkgname, item, 0.0f);
+ return 0;
+}
+
+static int change_pkgname_cb(const char *pkgname, const char *val, void *data)
+{
+ struct item *item;
+ char *new_pkgname;
+
+ DbgPrint("[%s] %s\n", pkgname, val);
+
+ item = find_item(pkgname);
+ if (!item)
+ return -ENOENT;
+
+ new_pkgname = strdup(val);
+ if (!new_pkgname) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ DbgFree(item->pkgname);
+ item->pkgname = new_pkgname;
+ return 0;
+}
+
+static int download_cb(const char *pkgname, const char *val, void *data)
+{
+ /* val = integer */
+ struct item *item;
+ double value;
+
+ DbgPrint("[%s] %s\n", pkgname, val);
+
+ item = find_item(pkgname);
+ if (!item) {
+ DbgPrint("ITEM is not started from the start_cb\n");
+ return -EINVAL;
+ }
+
+ if (item->type != PKGMGR_EVENT_DOWNLOAD) {
+ DbgPrint("TYPE is not \"download\" : %d\n", item->type);
+ item->type = PKGMGR_EVENT_DOWNLOAD;
+ }
+
+ switch (item->status) {
+ case PKGMGR_STATUS_START:
+ case PKGMGR_STATUS_COMMAND:
+ item->status = PKGMGR_STATUS_PROCESSING;
+ case PKGMGR_STATUS_PROCESSING:
+ break;
+ default:
+ ErrPrint("Invalid state [%s, %s]\n", pkgname, val);
+ return -EINVAL;
+ }
+
+ if (val) {
+ if (sscanf(val, "%lf", &value) != 1)
+ value = (double)-EINVAL;
+ } else {
+ value = (double)-EINVAL;
+ }
+
+ invoke_download_event_handler(pkgname, item->status, value);
+ return 0;
+}
+
+static int progress_cb(const char *pkgname, const char *val, void *data)
+{
+ /* val = integer */
+ struct item *item;
+ double value;
+
+ DbgPrint("[%s] %s\n", pkgname, val);
+
+ item = find_item(pkgname);
+ if (!item) {
+ ErrPrint("ITEM is not started from the start_cb\n");
+ return -EINVAL;
+ }
+
+ switch (item->status) {
+ case PKGMGR_STATUS_START:
+ case PKGMGR_STATUS_COMMAND:
+ item->status = PKGMGR_STATUS_PROCESSING;
+ case PKGMGR_STATUS_PROCESSING:
+ break;
+ default:
+ ErrPrint("Invalid state [%s, %s]\n", pkgname, val);
+ return -EINVAL;
+ }
+
+ if (val) {
+ if (sscanf(val, "%lf", &value) != 1)
+ value = (double)-EINVAL;
+ } else {
+ value = (double)-EINVAL;
+ }
+
+ invoke_callback(pkgname, item, value);
+ return 0;
+}
+
+static int end_cb(const char *pkgname, const char *val, void *data)
+{
+ struct item *item;
+
+ DbgPrint("[%s] %s\n", pkgname, val);
+
+ item = find_item(pkgname);
+ if (!item)
+ return -ENOENT;
+
+ item->status = !strcasecmp(val, "ok") ? PKGMGR_STATUS_END : PKGMGR_STATUS_ERROR;
+
+ invoke_callback(pkgname, item, 0.0f);
+
+ s_info.item_list = eina_list_remove(s_info.item_list, item);
+ DbgFree(item->icon);
+ DbgFree(item->pkgname);
+ DbgFree(item);
+ return 0;
+}
+
+static struct pkgmgr_handler {
+ const char *key;
+ int (*func)(const char *package, const char *val, void *data);
+} handler[] = {
+ { "install_percent", progress_cb },
+ { "download_percent", download_cb },
+ { "start", start_cb },
+ { "end", end_cb },
+ { "change_pkg_name", change_pkgname_cb },
+ { "icon_path", icon_path_cb },
+ { "command", command_cb },
+ { "error", error_cb },
+ { NULL, NULL },
+};
+
+static int pkgmgr_cb(int req_id, const char *type, const char *pkgname, const char *key, const char *val, const void *pmsg, void *data)
+{
+ register int i;
+ int ret;
+
+ for (i = 0; handler[i].key; i++) {
+ if (strcasecmp(key, handler[i].key))
+ continue;
+
+ ret = handler[i].func(pkgname, val, data);
+ DbgPrint("REQ[%d] pkgname[%s], type[%s], key[%s], val[%s], ret = %d\n",
+ req_id, pkgname, type, key, val, ret);
+ }
+
+ return 0;
+}
+
+HAPI int pkgmgr_init(void)
+{
+ if (s_info.listen_pc)
+ return -EALREADY;
+
+ s_info.listen_pc = pkgmgr_client_new(PC_LISTENING);
+ if (!s_info.listen_pc)
+ return -EFAULT;
+
+ if (pkgmgr_client_listen_status(s_info.listen_pc, pkgmgr_cb, NULL) != PKGMGR_R_OK)
+ return -EFAULT;
+
+ return 0;
+}
+
+HAPI int pkgmgr_fini(void)
+{
+ struct event_item *item;
+ struct item *ctx;
+
+ if (!s_info.listen_pc)
+ return -EINVAL;
+
+ if (pkgmgr_client_free(s_info.listen_pc) != PKGMGR_R_OK)
+ return -EFAULT;
+
+ s_info.listen_pc = NULL;
+
+ EINA_LIST_FREE(s_info.download_event, item) {
+ DbgFree(item);
+ }
+
+ EINA_LIST_FREE(s_info.uninstall_event, item) {
+ DbgFree(item);
+ }
+
+ EINA_LIST_FREE(s_info.install_event, item) {
+ DbgFree(item);
+ }
+
+ EINA_LIST_FREE(s_info.update_event, item) {
+ DbgFree(item);
+ }
+
+ EINA_LIST_FREE(s_info.recover_event, item) {
+ DbgFree(item);
+ }
+
+ EINA_LIST_FREE(s_info.item_list, ctx) {
+ DbgFree(ctx->pkgname);
+ DbgFree(ctx->icon);
+ DbgFree(ctx);
+ }
+
+ return 0;
+}
+
+HAPI 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)
+{
+ struct event_item *item;
+
+ item = calloc(1, sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ item->cb = cb;
+ item->data = data;
+
+ switch (type) {
+ case PKGMGR_EVENT_DOWNLOAD:
+ s_info.download_event = eina_list_prepend(s_info.download_event, item);
+ break;
+ case PKGMGR_EVENT_UNINSTALL:
+ s_info.uninstall_event = eina_list_prepend(s_info.uninstall_event, item);
+ break;
+ case PKGMGR_EVENT_INSTALL:
+ s_info.install_event = eina_list_prepend(s_info.install_event, item);
+ break;
+ case PKGMGR_EVENT_UPDATE:
+ s_info.update_event = eina_list_prepend(s_info.update_event, item);
+ break;
+ case PKGMGR_EVENT_RECOVER:
+ s_info.recover_event = eina_list_prepend(s_info.recover_event, item);
+ break;
+ default:
+ DbgFree(item);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+HAPI 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)
+{
+ struct event_item *item;
+ Eina_List *l;
+ void *cbdata = NULL;
+
+ switch (type) {
+ case PKGMGR_EVENT_DOWNLOAD:
+ EINA_LIST_FOREACH(s_info.download_event, l, item) {
+ if (item->cb == cb && item->data == data) {
+ s_info.download_event = eina_list_remove(s_info.download_event, item);
+ cbdata = item->data;
+ DbgFree(item);
+ break;
+ }
+ }
+ break;
+ case PKGMGR_EVENT_UNINSTALL:
+ EINA_LIST_FOREACH(s_info.uninstall_event, l, item) {
+ if (item->cb == cb && item->data == data) {
+ s_info.uninstall_event = eina_list_remove(s_info.uninstall_event, item);
+ cbdata = item->data;
+ DbgFree(item);
+ break;
+ }
+ }
+ break;
+ case PKGMGR_EVENT_INSTALL:
+ EINA_LIST_FOREACH(s_info.install_event, l, item) {
+ if (item->cb == cb && item->data == data) {
+ s_info.install_event = eina_list_remove(s_info.install_event, item);
+ cbdata = item->data;
+ DbgFree(item);
+ break;
+ }
+ }
+ break;
+ case PKGMGR_EVENT_UPDATE:
+ EINA_LIST_FOREACH(s_info.update_event, l, item) {
+ if (item->cb == cb && item->data == data) {
+ s_info.update_event = eina_list_remove(s_info.update_event, item);
+ cbdata = item->data;
+ DbgFree(item);
+ break;
+ }
+ }
+ break;
+ case PKGMGR_EVENT_RECOVER:
+ EINA_LIST_FOREACH(s_info.recover_event, l, item) {
+ if (item->cb == cb && item->data == data) {
+ s_info.recover_event = eina_list_remove(s_info.recover_event, item);
+ cbdata = item->data;
+ DbgFree(item);
+ break;
+ }
+ }
+ break;
+ default:
+ ErrPrint("Invalid type\n");
+ break;
+ }
+
+ return cbdata;
+}
+
+/* End of a file */
diff --git a/src/script_handler.c b/src/script_handler.c
new file mode 100644
index 0000000..2fe88da
--- /dev/null
+++ b/src/script_handler.c
@@ -0,0 +1,1317 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h> /* free */
+#include <ctype.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+
+#include <Ecore_Evas.h>
+#include <Ecore.h>
+#include <Evas.h>
+
+#include <dlog.h>
+#include <packet.h>
+
+#include "slave_life.h"
+#include "slave_rpc.h"
+#include "client_life.h"
+#include "package.h"
+#include "instance.h"
+#include "buffer_handler.h"
+#include "script_handler.h"
+#include "fb.h"
+#include "debug.h"
+#include "conf.h"
+#include "util.h"
+
+#define TYPE_COLOR "color"
+#define TYPE_TEXT "text"
+#define TYPE_IMAGE "image"
+#define TYPE_EDJE "script"
+#define TYPE_SIGNAL "signal"
+#define TYPE_INFO "info"
+#define TYPE_DRAG "drag"
+#define INFO_SIZE "size"
+#define INFO_CATEGORY "category"
+#define ADDEND 256
+
+int errno;
+
+static struct info {
+ Eina_List *script_port_list;
+ enum buffer_type env_buf_type;
+} s_info = {
+ .script_port_list = NULL,
+ .env_buf_type = BUFFER_TYPE_FILE,
+};
+
+struct script_port {
+ void *handle;
+
+ const char *(*magic_id)(void);
+ int (*update_color)(void *handle, Evas *e, const char *id, const char *part, const char *rgba);
+ int (*update_text)(void *handle, Evas *e, const char *id, const char *part, const char *text);
+ int (*update_image)(void *handle, Evas *e, const char *id, const char *part, const char *path, const char *option);
+ int (*update_script)(void *handle, Evas *e, const char *src_id, const char *target_id, const char *part, const char *path, const char *option);
+ int (*update_signal)(void *handle, Evas *e, const char *id, const char *part, const char *signal);
+ int (*update_drag)(void *handle, Evas *e, const char *id, const char *part, double x, double y);
+ int (*update_size)(void *handle, Evas *e, const char *id, int w, int h);
+ int (*update_category)(void *handle, Evas *e, const char *id, const char *category);
+
+ void *(*create)(const char *file, const char *option);
+ int (*destroy)(void *handle);
+
+ int (*load)(void *handle, Evas *e, int w, int h);
+ int (*unload)(void *handle, Evas *e);
+
+ int (*init)(void);
+ int (*fini)(void);
+};
+
+struct block {
+ char *type;
+ int type_len;
+
+ char *part;
+ int part_len;
+
+ char *data;
+ int data_len;
+
+ char *file;
+ int file_len;
+
+ char *option;
+ int option_len;
+
+ char *id;
+ int id_len;
+
+ char *target_id;
+ int target_len;
+};
+
+struct script_info {
+ Ecore_Evas *ee;
+ struct fb_info *fb;
+ struct inst_info *inst;
+ int loaded;
+
+ int w;
+ int h;
+
+ double x;
+ double y;
+ int down;
+
+ struct script_port *port;
+ void *port_data;
+};
+
+static inline struct script_port *find_port(const char *magic_id)
+{
+ Eina_List *l;
+ struct script_port *item;
+
+ EINA_LIST_FOREACH(s_info.script_port_list, l, item) {
+ if (!strcmp(item->magic_id(), magic_id))
+ return item;
+ }
+
+ return NULL;
+}
+
+static void render_pre_cb(void *data, Evas *e, void *event_info)
+{
+ struct inst_info *inst = data;
+ struct script_info *info;
+
+ if (instance_state(inst) != INST_ACTIVATED) {
+ DbgPrint("Render pre invoked but instance is not activated\n");
+ return;
+ }
+
+ info = instance_lb_script(inst);
+ if (info && script_handler_evas(info) == e) {
+ return;
+ }
+
+ info = instance_pd_script(inst);
+ if (info && script_handler_evas(info) == e) {
+ return;
+ }
+
+ ErrPrint("Failed to do sync\n");
+ return;
+}
+
+static void render_post_cb(void *data, Evas *e, void *event_info)
+{
+ struct inst_info *inst;
+ struct script_info *info;
+
+ inst = data;
+
+ if (instance_state(inst) != INST_ACTIVATED) {
+ DbgPrint("Render post invoked but instance is not activated\n");
+ return;
+ }
+
+ info = instance_lb_script(inst);
+ if (info && script_handler_evas(info) == e) {
+ fb_sync(script_handler_fb(info));
+ instance_lb_updated_by_instance(inst);
+ return;
+ }
+
+ info = instance_pd_script(inst);
+ if (info && script_handler_evas(info) == e) {
+ fb_sync(script_handler_fb(info));
+ instance_pd_updated_by_instance(inst, NULL);
+ return;
+ }
+
+ ErrPrint("Failed to sync\n");
+ return;
+}
+
+/*!
+ * \NOTE
+ * Exported API
+ */
+int script_signal_emit(Evas *e, const char *part, const char *signal, double sx, double sy, double ex, double ey)
+{
+ Ecore_Evas *ee;
+ struct script_info *info;
+ int ret;
+
+ ee = ecore_evas_ecore_evas_get(e);
+ if (!ee) {
+ ErrPrint("Evas has no Ecore_Evas\n");
+ return -EINVAL;
+ }
+
+ info = ecore_evas_data_get(ee, "script,info");
+ if (!info) {
+ ErrPrint("ecore_evas doesn't carry info data\n");
+ return -EINVAL;
+ }
+
+ if (!signal || strlen(signal) == 0)
+ signal = "";
+
+ if (!part || strlen(part) == 0)
+ part = "";
+
+ ret = instance_signal_emit(info->inst, signal, part, sx, sy, ex, ey, info->x, info->y, info->down);
+ return ret;
+}
+
+HAPI int script_handler_load(struct script_info *info, int is_pd)
+{
+ int ret;
+ Evas *e;
+
+ if (!info || !info->port) {
+ ErrPrint("Script handler is not created\n");
+ return -EINVAL;
+ }
+
+ if (info->loaded > 0) {
+ info->loaded++;
+ return 0;
+ }
+
+ ret = fb_create_buffer(info->fb);
+ if (ret < 0)
+ return ret;
+
+ info->ee = fb_canvas(info->fb);
+ if (!info->ee) {
+ ErrPrint("Failed to get canvas\n");
+ fb_destroy_buffer(info->fb);
+ return -EFAULT;
+ }
+
+ ecore_evas_data_set(info->ee, "script,info", info);
+
+ e = script_handler_evas(info);
+ if (e) {
+ evas_event_callback_add(e, EVAS_CALLBACK_RENDER_PRE, render_pre_cb, info->inst);
+ evas_event_callback_add(e, EVAS_CALLBACK_RENDER_POST, render_post_cb, info->inst);
+ if (info->port->load(info->port_data, e, info->w, info->h) < 0) {
+ ErrPrint("Failed to add new script object\n");
+ evas_event_callback_del(e, EVAS_CALLBACK_RENDER_POST, render_post_cb);
+ evas_event_callback_del(e, EVAS_CALLBACK_RENDER_PRE, render_pre_cb);
+ fb_destroy_buffer(info->fb);
+ return -EFAULT;
+ }
+ info->loaded = 1;
+ script_signal_emit(e, util_uri_to_path(instance_id(info->inst)),
+ is_pd ? "pd,show" : "lb,show", 0.0f, 0.0f, 0.0f, 0.0f);
+ } else {
+ ErrPrint("Evas: (nil) %dx%d\n", info->w, info->h);
+ }
+
+ ecore_evas_manual_render_set(info->ee, EINA_FALSE);
+ ecore_evas_resize(info->ee, info->w, info->h);
+ ecore_evas_show(info->ee);
+ ecore_evas_activate(info->ee);
+ fb_sync(info->fb);
+
+ return 0;
+}
+
+HAPI int script_handler_unload(struct script_info *info, int is_pd)
+{
+ Ecore_Evas *ee;
+ Evas *e;
+
+ if (!info || !info->port)
+ return -EINVAL;
+
+ info->loaded--;
+ if (info->loaded > 0)
+ return 0;
+
+ if (info->loaded < 0) {
+ info->loaded = 0;
+ return 0;
+ }
+
+ e = script_handler_evas(info);
+ if (e) {
+ script_signal_emit(e, util_uri_to_path(instance_id(info->inst)),
+ is_pd ? "pd,hide" : "lb,hide", 0.0f, 0.0f, 0.0f, 0.0f);
+ if (info->port->unload(info->port_data, e) < 0)
+ ErrPrint("Failed to unload script object. but go ahead\n");
+ evas_event_callback_del(e, EVAS_CALLBACK_RENDER_POST, render_post_cb);
+ evas_event_callback_del(e, EVAS_CALLBACK_RENDER_PRE, render_pre_cb);
+ } else {
+ ErrPrint("Evas(nil): Unload script\n");
+ }
+
+ ee = fb_canvas(info->fb);
+ if (ee)
+ ecore_evas_data_set(ee, "script,info", NULL);
+
+ fb_destroy_buffer(info->fb);
+ return 0;
+}
+
+HAPI struct script_info *script_handler_create(struct inst_info *inst, const char *file, const char *option, int w, int h)
+{
+ struct script_info *info;
+
+ DbgPrint("Create script: %s (%s)\n", file, option);
+
+ if (!file)
+ return NULL;
+
+ info = calloc(1, sizeof(*info));
+ if (!info) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ info->fb = fb_create(inst, w, h, s_info.env_buf_type);
+ if (!info->fb) {
+ ErrPrint("Failed to create a FB (%dx%d)\n", w, h);
+ DbgFree(info);
+ return NULL;
+ }
+
+ info->inst = inst;
+ info->port = find_port(package_script(instance_package(inst)));
+ if (!info->port) {
+ ErrPrint("Failed to find a proper port for [%s]%s\n",
+ instance_package(inst), package_script(instance_package(inst)));
+ fb_destroy(info->fb);
+ DbgFree(info);
+ return NULL;
+ }
+
+ DbgPrint("Update info [%dx%d]\n", w, h);
+ info->w = w;
+ info->h = h;
+
+ info->port_data = info->port->create(file, option);
+ if (!info->port_data) {
+ ErrPrint("Failed to create a port (%s - %s)\n", file, option);
+ fb_destroy(info->fb);
+ DbgFree(info);
+ return NULL;
+ }
+
+ return info;
+}
+
+HAPI int script_handler_destroy(struct script_info *info)
+{
+ if (!info || !info->port) {
+ ErrPrint("port is not valid\n");
+ return -EINVAL;
+ }
+
+ if (info->loaded != 0) {
+ ErrPrint("Script handler is not unloaded\n");
+ return -EINVAL;
+ }
+
+ if (info->port->destroy(info->port_data) < 0)
+ ErrPrint("Failed to destroy port, but go ahead\n");
+
+ fb_destroy(info->fb);
+ DbgFree(info);
+ return 0;
+}
+
+HAPI int script_handler_is_loaded(struct script_info *info)
+{
+ return info ? info->loaded > 0 : 0;
+}
+
+HAPI struct fb_info *script_handler_fb(struct script_info *info)
+{
+ return info ? info->fb : NULL;
+}
+
+HAPI void *script_handler_evas(struct script_info *info)
+{
+ if (!info)
+ return NULL;
+
+ if (!info->ee)
+ return NULL;
+
+ return ecore_evas_get(info->ee);
+}
+
+static int update_script_color(struct inst_info *inst, struct block *block, int is_pd)
+{
+ struct script_info *info;
+ Evas *e;
+
+ if (!block || !block->part || !block->data) {
+ ErrPrint("Block or part or data is not valid\n");
+ return -EINVAL;
+ }
+
+ info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
+ if (!info) {
+ ErrPrint("info is NIL\n");
+ return -EFAULT;
+ }
+
+ if (!info->port) {
+ ErrPrint("info->port is NIL\n");
+ return -EINVAL;
+ }
+
+ e = script_handler_evas(info);
+ if (e)
+ info->port->update_color(info->port_data, e, block->id, block->part, block->data);
+ else
+ ErrPrint("Evas(nil) id[%s] part[%s] data[%s]\n", block->id, block->part, block->data);
+
+ return 0;
+}
+
+static int update_script_text(struct inst_info *inst, struct block *block, int is_pd)
+{
+ struct script_info *info;
+ Evas *e;
+
+ if (!block || !block->part || !block->data) {
+ ErrPrint("Block or part or data is not valid\n");
+ return -EINVAL;
+ }
+
+ info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
+ if (!info) {
+ ErrPrint("info is NIL\n");
+ return -EFAULT;
+ }
+
+ if (!info->port) {
+ ErrPrint("info->port is NIL\n");
+ return -EINVAL;
+ }
+
+ e = script_handler_evas(info);
+ if (e)
+ info->port->update_text(info->port_data, e, block->id, block->part, block->data);
+ else
+ ErrPrint("Evas(nil) id[%s] part[%s] data[%s]\n", block->id, block->part, block->data);
+ return 0;
+}
+
+static int update_script_image(struct inst_info *inst, struct block *block, int is_pd)
+{
+ struct script_info *info;
+ Evas *e;
+
+ if (!block || !block->part) {
+ ErrPrint("Block or part is not valid\n");
+ return -EINVAL;
+ }
+
+ info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
+ if (!info) {
+ ErrPrint("info is NIL\n");
+ return -EFAULT;
+ }
+
+ if (!info->port) {
+ ErrPrint("info->port is NIL\n");
+ return -EINVAL;
+ }
+
+ e = script_handler_evas(info);
+ if (e)
+ info->port->update_image(info->port_data, e, block->id, block->part, block->data, block->option);
+ else
+ ErrPrint("Evas: (nil) id[%s] part[%s] data[%s]\n", block->id, block->part, block->data);
+ return 0;
+}
+
+static int update_script_script(struct inst_info *inst, struct block *block, int is_pd)
+{
+ struct script_info *info;
+ Evas *e;
+
+ if (!block || !block->part) {
+ ErrPrint("Block or part is NIL\n");
+ return -EINVAL;
+ }
+
+ info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
+ if (!info) {
+ ErrPrint("info is NIL\n");
+ return -EFAULT;
+ }
+
+ if (!info->port) {
+ ErrPrint("info->port is NIL\n");
+ return -EINVAL;
+ }
+
+ e = script_handler_evas(info);
+ if (e)
+ info->port->update_script(info->port_data, e, block->id, block->target_id, block->part, block->data, block->option);
+ else
+ ErrPrint("Evas: (nil) id[%s] part[%s] data[%s] option[%s]\n",
+ block->id, block->part, block->data, block->option);
+ return 0;
+}
+
+static int update_script_signal(struct inst_info *inst, struct block *block, int is_pd)
+{
+ struct script_info *info;
+ Evas *e;
+
+ if (!block) {
+ ErrPrint("block is NIL\n");
+ return -EINVAL;
+ }
+
+ info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
+ if (!info) {
+ ErrPrint("info is NIL\n");
+ return -EFAULT;
+ }
+
+ if (!info->port) {
+ ErrPrint("info->port is NIL\n");
+ return -EINVAL;
+ }
+
+ e = script_handler_evas(info);
+ if (e)
+ info->port->update_signal(info->port_data, e, block->id, block->part, block->data);
+ else
+ ErrPrint("Evas(nil) id[%s] part[%s] data[%s]\n", block->id, block->part, block->data);
+ return 0;
+}
+
+static int update_script_drag(struct inst_info *inst, struct block *block, int is_pd)
+{
+ struct script_info *info;
+ double dx, dy;
+ Evas *e;
+
+ if (!block || !block->data || !block->part) {
+ ErrPrint("block or block->data or block->part is NIL\n");
+ return -EINVAL;
+ }
+
+ info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
+ if (!info) {
+ ErrPrint("info is NIL\n");
+ return -EFAULT;
+ }
+
+ if (sscanf(block->data, "%lfx%lf", &dx, &dy) != 2) {
+ ErrPrint("Invalid format of data (DRAG data [%s])\n", block->data);
+ return -EINVAL;
+ }
+
+ if (!info->port) {
+ ErrPrint("info->port is NIL\n");
+ return -EINVAL;
+ }
+
+ e = script_handler_evas(info);
+ if (e)
+ info->port->update_drag(info->port_data, e, block->id, block->part, dx, dy);
+ else
+ ErrPrint("Evas(nil) id[%s] part[%s] %lfx%lf\n", block->id, block->part, dx, dy);
+ return 0;
+}
+
+HAPI int script_handler_resize(struct script_info *info, int w, int h)
+{
+ if (!info) {
+ //|| (info->w == w && info->h == h)) {
+ ErrPrint("info[%p] resize is not changed\n", info);
+ return 0;
+ }
+
+ fb_resize(script_handler_fb(info), w, h);
+
+ if (info->port->update_size) {
+ Evas *e;
+ e = script_handler_evas(info);
+ if (e)
+ info->port->update_size(info->port_data, e, NULL , w, h);
+ else
+ ErrPrint("Evas(nil) resize to %dx%d\n", w, h);
+ }
+
+ info->w = w;
+ info->h = h;
+
+ return 0;
+}
+
+static int update_info(struct inst_info *inst, struct block *block, int is_pd)
+{
+ struct script_info *info;
+
+ if (!block || !block->part || !block->data) {
+ ErrPrint("block or block->part or block->data is NIL\n");
+ return -EINVAL;
+ }
+
+ info = is_pd ? instance_pd_script(inst) : instance_lb_script(inst);
+ if (!info) {
+ ErrPrint("info is NIL\n");
+ return -EFAULT;
+ }
+
+ if (!info->port) {
+ ErrPrint("info->port is NIL\n");
+ return -EINVAL;
+ }
+
+ if (!strcasecmp(block->part, INFO_SIZE)) {
+ Evas_Coord w, h;
+
+ if (sscanf(block->data, "%dx%d", &w, &h) != 2) {
+ ErrPrint("Invalid format for SIZE(%s)\n", block->data);
+ return -EINVAL;
+ }
+
+ if (!block->id) {
+ int resized;
+
+ if (is_pd) {
+ resized = (instance_pd_width(inst) != w) || (instance_pd_height(inst) != h);
+ instance_set_pd_info(inst, w, h);
+ } else {
+ /*!
+ * \note
+ * LB Size is already scaled by livebox-service.
+ * Each livebox uses the LB_SIZE_TYPE_XXX for its size.
+ */
+ resized = (instance_lb_width(inst) != w) || (instance_lb_height(inst) != h);
+ instance_set_lb_info(inst, w, h, PRIORITY_NO_CHANGE, CONTENT_NO_CHANGE, TITLE_NO_CHANGE);
+ }
+
+ if (resized)
+ instance_send_resized_event(inst, is_pd, w, h, 0);
+
+ script_handler_resize(info, w, h);
+ } else {
+ Evas *e;
+ e = script_handler_evas(info);
+ if (e)
+ info->port->update_size(info->port_data, e, block->id, w, h);
+ else
+ ErrPrint("Evas(nil): id[%s] %dx%d\n", block->id, w, h);
+ }
+ } else if (!strcasecmp(block->part, INFO_CATEGORY)) {
+ Evas *e;
+ e = script_handler_evas(info);
+ if (e)
+ info->port->update_category(info->port_data, e, block->id, block->data);
+ else
+ ErrPrint("Evas(nil): id[%s] data[%s]\n", block->id, block->data);
+ }
+
+ return 0;
+}
+
+HAPI int script_handler_parse_desc(const char *pkgname, const char *id, const char *descfile, int is_pd)
+{
+ struct inst_info *inst;
+ FILE *fp;
+ int ch;
+ int lineno;
+ enum state {
+ UNKNOWN = 0x10,
+ BLOCK_OPEN = 0x11,
+ FIELD = 0x12,
+ VALUE = 0x13,
+ BLOCK_CLOSE = 0x14,
+
+ VALUE_TYPE = 0x00,
+ VALUE_PART = 0x01,
+ VALUE_DATA = 0x02,
+ VALUE_FILE = 0x03,
+ VALUE_OPTION = 0x04,
+ VALUE_ID = 0x05,
+ VALUE_TARGET = 0x06,
+ };
+ const char *field_name[] = {
+ "type",
+ "part",
+ "data",
+ "file",
+ "option",
+ "id",
+ "target",
+ NULL
+ };
+ enum state state;
+ register int field_idx;
+ register int idx = 0;
+ register int i;
+ struct block *block;
+ struct {
+ const char *type;
+ int (*handler)(struct inst_info *inst, struct block *block, int is_pd);
+ } handlers[] = {
+ {
+ .type = TYPE_COLOR,
+ .handler = update_script_color,
+ },
+ {
+ .type = TYPE_TEXT,
+ .handler = update_script_text,
+ },
+ {
+ .type = TYPE_IMAGE,
+ .handler = update_script_image,
+ },
+ {
+ .type = TYPE_EDJE,
+ .handler = update_script_script,
+ },
+ {
+ .type = TYPE_SIGNAL,
+ .handler = update_script_signal,
+ },
+ {
+ .type = TYPE_DRAG,
+ .handler = update_script_drag,
+ },
+ {
+ .type = TYPE_INFO,
+ .handler = update_info,
+ },
+ {
+ .type = NULL,
+ .handler = NULL,
+ },
+ };
+
+ block = NULL;
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance is not exists\n");
+ return -ENOENT;
+ }
+
+ fp = fopen(descfile, "rt");
+ if (!fp) {
+ ErrPrint("Error: %s [%s]\n", descfile, strerror(errno));
+ return -EIO;
+ }
+
+ state = UNKNOWN;
+ field_idx = 0;
+ lineno = 1;
+
+ block = NULL;
+ while (!feof(fp)) {
+ ch = getc(fp);
+ if (ch == '\n')
+ lineno++;
+
+ switch (state) {
+ case UNKNOWN:
+ if (ch == '{') {
+ state = BLOCK_OPEN;
+ break;
+ }
+
+ if (!isspace(ch) && ch != EOF) {
+ ErrPrint("%d: Syntax error: Desc is not started with '{' or space - (%c = 0x%x)\n", lineno, ch, ch);
+ fclose(fp);
+ return -EINVAL;
+ }
+ break;
+
+ case BLOCK_OPEN:
+ if (isblank(ch))
+ break;
+
+ if (ch != '\n') {
+ ErrPrint("%d: Syntax error: New line must has to be started right after '{'\n", lineno);
+ goto errout;
+ }
+
+ block = calloc(1, sizeof(*block));
+ if (!block) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ fclose(fp);
+ return -ENOMEM;
+ }
+
+ state = FIELD;
+ idx = 0;
+ field_idx = 0;
+ break;
+
+ case FIELD:
+ if (isspace(ch))
+ break;
+
+ if (ch == '}') {
+ state = BLOCK_CLOSE;
+ break;
+ }
+
+ if (ch == '=') {
+ if (field_name[field_idx][idx] != '\0') {
+ ErrPrint("%d: Syntax error: Unrecognized field\n", lineno);
+ goto errout;
+ }
+
+ switch (field_idx) {
+ case 0:
+ state = VALUE_TYPE;
+ if (block->type) {
+ DbgFree(block->type);
+ block->type = NULL;
+ block->type_len = 0;
+ }
+ idx = 0;
+ break;
+ case 1:
+ state = VALUE_PART;
+ if (block->part) {
+ DbgFree(block->part);
+ block->part = NULL;
+ block->part_len = 0;
+ }
+ idx = 0;
+ break;
+ case 2:
+ state = VALUE_DATA;
+ if (block->data) {
+ DbgFree(block->data);
+ block->data = NULL;
+ block->data_len = 0;
+ }
+ idx = 0;
+ break;
+ case 3:
+ state = VALUE_FILE;
+ if (block->file) {
+ DbgFree(block->file);
+ block->file = NULL;
+ block->file_len = 0;
+ }
+ idx = 0;
+ break;
+ case 4:
+ state = VALUE_OPTION;
+ if (block->option) {
+ DbgFree(block->option);
+ block->option = NULL;
+ block->option_len = 0;
+ }
+ idx = 0;
+ break;
+ case 5:
+ state = VALUE_ID;
+ if (block->id) {
+ DbgFree(block->id);
+ block->id = NULL;
+ block->id_len = 0;
+ }
+ idx = 0;
+ break;
+ case 6:
+ state = VALUE_TARGET;
+ if (block->target_id) {
+ DbgFree(block->target_id);
+ block->target_id = NULL;
+ block->target_len = 0;
+ }
+ idx = 0;
+ break;
+ default:
+ ErrPrint("%d: Syntax error: Unrecognized field\n", lineno);
+ goto errout;
+ }
+
+ break;
+ }
+
+ if (ch == '\n')
+ goto errout;
+
+ if (field_name[field_idx][idx] != ch) {
+ ungetc(ch, fp);
+ if (ch == '\n')
+ lineno--;
+
+ while (--idx >= 0)
+ ungetc(field_name[field_idx][idx], fp);
+
+ field_idx++;
+ if (field_name[field_idx] == NULL) {
+ ErrPrint("%d: Syntax error: Unrecognized field\n", lineno);
+ goto errout;
+ }
+
+ idx = 0;
+ break;
+ }
+
+ idx++;
+ break;
+
+ case VALUE_TYPE:
+ if (idx == block->type_len) {
+ char *tmp;
+ block->type_len += ADDEND;
+ tmp = realloc(block->type, block->type_len);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ goto errout;
+ }
+ block->type = tmp;
+ }
+
+ if (ch == '\n') {
+ block->type[idx] = '\0';
+ state = FIELD;
+ idx = 0;
+ field_idx = 0;
+ break;
+ }
+
+ block->type[idx] = ch;
+ idx++;
+ break;
+
+ case VALUE_PART:
+ if (idx == block->part_len) {
+ char *tmp;
+ block->part_len += ADDEND;
+ tmp = realloc(block->part, block->part_len);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ goto errout;
+ }
+ block->part = tmp;
+ }
+
+ if (ch == '\n') {
+ block->part[idx] = '\0';
+ state = FIELD;
+ idx = 0;
+ field_idx = 0;
+ break;
+ }
+
+ block->part[idx] = ch;
+ idx++;
+ break;
+
+ case VALUE_DATA:
+ if (idx == block->data_len) {
+ char *tmp;
+ block->data_len += ADDEND;
+ tmp = realloc(block->data, block->data_len);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ goto errout;
+ }
+ block->data = tmp;
+ }
+
+ if (ch == '\n') {
+ block->data[idx] = '\0';
+ state = FIELD;
+ idx = 0;
+ field_idx = 0;
+ break;
+ }
+
+ block->data[idx] = ch;
+ idx++;
+ break;
+
+ case VALUE_FILE:
+ if (idx == block->file_len) {
+ char *tmp;
+ block->file_len += ADDEND;
+ tmp = realloc(block->file, block->file_len);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ goto errout;
+ }
+ block->file = tmp;
+ }
+
+ if (ch == '\n') {
+ block->file[idx] = '\0';
+ state = FIELD;
+ idx = 0;
+ field_idx = 0;
+ break;
+ }
+
+ block->file[idx] = ch;
+ idx++;
+ break;
+
+ case VALUE_OPTION:
+ if (idx == block->option_len) {
+ char *tmp;
+ block->option_len += ADDEND;
+ tmp = realloc(block->option, block->option_len);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ goto errout;
+ }
+ block->option = tmp;
+ }
+
+ if (ch == '\n') {
+ block->option[idx] = '\0';
+ state = FIELD;
+ idx = 0;
+ field_idx = 0;
+ break;
+ }
+
+ block->option[idx] = ch;
+ idx++;
+ break;
+ case VALUE_ID:
+ if (idx == block->id_len) {
+ char *tmp;
+ block->id_len += ADDEND;
+ tmp = realloc(block->id, block->id_len);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ goto errout;
+ }
+ block->id = tmp;
+ }
+
+ if (ch == '\n') {
+ block->id[idx] = '\0';
+ state = FIELD;
+ idx = 0;
+ field_idx = 0;
+ break;
+ }
+
+ block->id[idx] = ch;
+ idx++;
+ break;
+ case VALUE_TARGET:
+ if (idx == block->target_len) {
+ char *tmp;
+ block->target_len += ADDEND;
+ tmp = realloc(block->target_id, block->target_len);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ goto errout;
+ }
+ block->target_id = tmp;
+ }
+
+ if (ch == '\n') {
+ block->target_id[idx] = '\0';
+ state = FIELD;
+ idx = 0;
+ field_idx = 0;
+ break;
+ }
+
+ block->target_id[idx] = ch;
+ idx++;
+ break;
+ case BLOCK_CLOSE:
+ if (!block->file) {
+ block->file = strdup(util_uri_to_path(id));
+ if (!block->file) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ goto errout;
+ }
+ }
+
+ i = 0;
+ while (handlers[i].type) {
+ if (!strcasecmp(handlers[i].type, block->type)) {
+ handlers[i].handler(inst, block, is_pd);
+ break;
+ }
+ i++;
+ }
+
+ if (!handlers[i].type)
+ ErrPrint("%d: Unknown block type: %s\n", lineno, block->type);
+
+ DbgFree(block->file);
+ DbgFree(block->type);
+ DbgFree(block->part);
+ DbgFree(block->data);
+ DbgFree(block->option);
+ DbgFree(block->id);
+ DbgFree(block->target_id);
+ DbgFree(block);
+ block = NULL;
+
+ state = UNKNOWN;
+ break;
+
+ default:
+ break;
+ } /* switch */
+ } /* while */
+
+ if (state != UNKNOWN) {
+ ErrPrint("%d: Unknown state\n", lineno);
+ goto errout;
+ }
+
+ fclose(fp);
+ return 0;
+
+errout:
+ ErrPrint("Parse error at %d file %s\n", lineno, util_basename(descfile));
+ if (block) {
+ DbgFree(block->file);
+ DbgFree(block->type);
+ DbgFree(block->part);
+ DbgFree(block->data);
+ DbgFree(block->option);
+ DbgFree(block->id);
+ DbgFree(block->target_id);
+ DbgFree(block);
+ }
+ fclose(fp);
+ return -EINVAL;
+}
+
+HAPI int script_init(void)
+{
+ struct script_port *item;
+ struct dirent *ent;
+ DIR *dir;
+ char *path;
+ int pathlen;
+
+ 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;
+
+ dir = opendir(SCRIPT_PORT_PATH);
+ if (!dir) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ return -EIO;
+ }
+
+ while ((ent = readdir(dir))) {
+ if (ent->d_name[0] == '.')
+ continue;
+
+ pathlen = strlen(ent->d_name) + strlen(SCRIPT_PORT_PATH) + 1;
+ path = malloc(pathlen);
+ if (!path) {
+ ErrPrint("Heap: %s %d\n", strerror(errno), pathlen);
+ closedir(dir);
+ return -ENOMEM;
+ }
+
+ snprintf(path, pathlen, "%s%s", SCRIPT_PORT_PATH, ent->d_name);
+
+ item = malloc(sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(path);
+ closedir(dir);
+ return -ENOMEM;
+ }
+
+ DbgPrint("Open SCRIPT PORT: %s\n", path);
+ item->handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW | RTLD_DEEPBIND);
+ DbgFree(path);
+ if (!item->handle) {
+ ErrPrint("Error: %s\n", dlerror());
+ DbgFree(item);
+ closedir(dir);
+ return -EFAULT;
+ }
+
+ item->magic_id = dlsym(item->handle, "script_magic_id");
+ if (!item->magic_id)
+ goto errout;
+
+ DbgPrint("SCRIPT PORT magic id: %s\n", item->magic_id());
+
+ item->update_color = dlsym(item->handle, "script_update_color");
+ if (!item->update_color)
+ goto errout;
+
+ item->update_text = dlsym(item->handle, "script_update_text");
+ if (!item->update_text)
+ goto errout;
+
+ item->update_image = dlsym(item->handle, "script_update_image");
+ if (!item->update_image)
+ goto errout;
+
+ item->update_script = dlsym(item->handle, "script_update_script");
+ if (!item->update_script)
+ goto errout;
+
+ item->update_signal = dlsym(item->handle, "script_update_signal");
+ if (!item->update_signal)
+ goto errout;
+
+ item->update_drag = dlsym(item->handle, "script_update_drag");
+ if (!item->update_drag)
+ goto errout;
+
+ item->update_size = dlsym(item->handle, "script_update_size");
+ if (!item->update_size)
+ goto errout;
+
+ item->update_category = dlsym(item->handle, "script_update_category");
+ if (!item->update_category)
+ goto errout;
+
+ item->create = dlsym(item->handle, "script_create");
+ if (!item->create)
+ goto errout;
+
+ item->destroy = dlsym(item->handle, "script_destroy");
+ if (!item->destroy)
+ goto errout;
+
+ item->load = dlsym(item->handle, "script_load");
+ if (!item->load)
+ goto errout;
+
+ item->unload = dlsym(item->handle, "script_unload");
+ if (!item->unload)
+ goto errout;
+
+ item->init = dlsym(item->handle, "script_init");
+ if (!item->init)
+ goto errout;
+
+ item->fini = dlsym(item->handle, "script_fini");
+ if (!item->fini)
+ goto errout;
+
+ if (item->init() < 0) {
+ ErrPrint("Failed to initialize script engine\n");
+ goto errout;
+ }
+
+ s_info.script_port_list = eina_list_append(s_info.script_port_list, item);
+ }
+
+ closedir(dir);
+ return 0;
+
+errout:
+ ErrPrint("Error: %s\n", dlerror());
+ dlclose(item->handle);
+ DbgFree(item);
+ closedir(dir);
+ return -EFAULT;
+}
+
+HAPI int script_fini(void)
+{
+ struct script_port *item;
+ /*!
+ * \TODO: Release all handles
+ */
+ EINA_LIST_FREE(s_info.script_port_list, item) {
+ item->fini();
+ dlclose(item->handle);
+ DbgFree(item);
+ }
+
+ return 0;
+}
+
+HAPI int script_handler_update_pointer(struct script_info *info, double x, double y, int down)
+{
+ if (!info)
+ return 0;
+
+ info->x = x;
+ info->y = y;
+
+ if (down == 0)
+ info->down = 0;
+ else if (down == 1)
+ info->down = 1;
+
+ return 0;
+}
+
+/* End of a file */
diff --git a/src/server.c b/src/server.c
new file mode 100644
index 0000000..c22c399
--- /dev/null
+++ b/src/server.c
@@ -0,0 +1,5572 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <dlog.h>
+#include <Evas.h>
+#include <Ecore_Evas.h> /* fb.h */
+#include <aul.h>
+#include <Ecore.h>
+
+#include <packet.h>
+#include <com-core_packet.h>
+
+#include "conf.h"
+#include "debug.h"
+#include "server.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 "util.h"
+#include "fault_manager.h"
+#include "fb.h" /* fb_type */
+#include "group.h"
+#include "xmonitor.h"
+#include "abi.h"
+#include "liveinfo.h"
+#include "io.h"
+
+static struct info {
+ int info_fd;
+ int client_fd;
+ int service_fd;
+ int slave_fd;
+} s_info = {
+ .info_fd = -1,
+ .client_fd = -1,
+ .service_fd = -1,
+ .slave_fd = -1,
+};
+
+/* Share this with provider */
+enum target_type {
+ TYPE_LB,
+ TYPE_PD,
+ TYPE_ERROR,
+};
+
+struct deleted_item {
+ struct client_node *client;
+ struct inst_info *inst;
+};
+
+static struct packet *client_acquire(pid_t pid, int handle, const struct packet *packet) /*!< timestamp, ret */
+{
+ struct client_node *client;
+ struct packet *result;
+ double timestamp;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (client) {
+ ErrPrint("Client is already exists %d\n", pid);
+ ret = -EEXIST;
+ goto out;
+ }
+
+ if (packet_get(packet, "d", &timestamp) != 1) {
+ ErrPrint("Invalid arguemnt\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("Acquired %lf\n", timestamp);
+
+ ret = 0;
+ /*!
+ * \note
+ * client_create will invoke the client created callback
+ */
+ client = client_create(pid, handle);
+ if (!client) {
+ ErrPrint("Failed to create a new client for %d\n", pid);
+ ret = -EFAULT;
+ }
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *cilent_release(pid_t pid, int handle, const struct packet *packet) /*!< pid, ret */
+{
+ struct client_node *client;
+ struct packet *result;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ client_destroy(client);
+ ret = 0;
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+/*!< pid, pkgname, filename, event, timestamp, x, y, ret */
+static struct packet *client_clicked(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ const char *event;
+ double timestamp;
+ double x;
+ double y;
+ int ret;
+ struct inst_info *inst;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "sssddd", &pkgname, &id, &event, &timestamp, &x, &y);
+ if (ret != 6) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s] id[%s] event[%s] timestamp[%lf] x[%lf] y[%lf]\n", pid, pkgname, id, event, timestamp, x, y);
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst)
+ ret = -ENOENT;
+ else if (package_is_fault(instance_package(inst)))
+ ret = -EFAULT;
+ else
+ ret = instance_clicked(inst, event, timestamp, x, y);
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+/* pid, pkgname, filename, emission, source, s, sy, ex, ey, ret */
+static struct packet *client_text_signal(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ struct packet *result;
+ const char *pkgname;
+ const char *id;
+ const char *emission;
+ const char *source;
+ double sx;
+ double sy;
+ double ex;
+ double ey;
+ struct inst_info *inst;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssssdddd", &pkgname, &id, &emission, &source, &sx, &sy, &ex, &ey);
+ if (ret != 8) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s] id[%s] emission[%s] source[%s] sx[%lf] sy[%lf] ex[%lf] ey[%lf]\n", pid, pkgname, id, emission, source, sx, sy, ex, ey);
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst)
+ ret = -ENOENT;
+ else if (package_is_fault(instance_package(inst)))
+ ret = -EFAULT;
+ else
+ ret = instance_text_signal_emit(inst, emission, source, sx, sy, ex, ey);
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static Eina_Bool lazy_delete_cb(void *data)
+{
+ struct deleted_item *item = data;
+
+ DbgPrint("Send delete event to the client\n");
+
+ /*!
+ * Before invoke this callback, the instance is able to already remove this client
+ * So check it again
+ */
+ if (instance_has_client(item->inst, item->client)) {
+ instance_unicast_deleted_event(item->inst, item->client);
+ instance_del_client(item->inst, item->client);
+ }
+
+ client_unref(item->client);
+ instance_unref(item->inst);
+ DbgFree(item);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static struct packet *client_delete(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, ret */
+{
+ struct client_node *client;
+ struct packet *result;
+ const char *pkgname;
+ const char *id;
+ struct inst_info *inst;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ss", &pkgname, &id);
+ if (ret != 2) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s] id[%s]\n", pid, pkgname, id);
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ret = -ENOENT;
+ } else if (package_is_fault(instance_package(inst))) {
+ ret = -EFAULT;
+ } else if (instance_client(inst) != client) {
+ if (instance_has_client(inst, client)) {
+ struct deleted_item *item;
+
+ item = malloc(sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ ret = -ENOMEM;
+ } else {
+ ret = 0;
+ /*!
+ * \NOTE:
+ * Send DELETED EVENT to the client.
+ * after return from this function.
+ *
+ * Client will prepare the deleted event after get this function's return value.
+ * So We have to make a delay to send a deleted event.
+ */
+
+ item->client = client_ref(client);
+ item->inst = instance_ref(inst);
+
+ if (!ecore_timer_add(DELAY_TIME, lazy_delete_cb, item)) {
+ ErrPrint("Failed to add a delayzed delete callback\n");
+ client_unref(client);
+ instance_unref(inst);
+ DbgFree(item);
+ ret = -EFAULT;
+ }
+ }
+ } else {
+ ret = -EPERM;
+ }
+ } else {
+ ret = instance_destroy(inst);
+ }
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *client_resize(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, w, h, ret */
+{
+ struct client_node *client;
+ struct packet *result;
+ const char *pkgname;
+ const char *id;
+ int w;
+ int h;
+ struct inst_info *inst;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssii", &pkgname, &id, &w, &h);
+ if (ret != 4) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s] id[%s] w[%d] h[%d]\n", pid, pkgname, id, w, h);
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ret = -ENOENT;
+ } else if (package_is_fault(instance_package(inst))) {
+ ret = -EFAULT;
+ } else if (instance_client(inst) != client) {
+ ret = -EPERM;
+ } else {
+ ret = instance_resize(inst, w, h);
+ }
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *client_new(pid_t pid, int handle, const struct packet *packet) /* pid, timestamp, pkgname, content, cluster, category, period, ret */
+{
+ struct client_node *client;
+ struct packet *result;
+ const char *pkgname;
+ const char *content;
+ const char *cluster;
+ const char *category;
+ double period;
+ double timestamp;
+ int ret;
+ struct pkg_info *info;
+ int width;
+ int height;
+ char *lb_pkgname;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "dssssdii", &timestamp, &pkgname, &content, &cluster, &category, &period, &width, &height);
+ if (ret != 8) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] period[%lf] pkgname[%s] content[%s] cluster[%s] category[%s] period[%lf]\n",
+ pid, timestamp, pkgname, content, cluster, category, period);
+
+ lb_pkgname = package_lb_pkgname(pkgname);
+ if (!lb_pkgname) {
+ ErrPrint("This %s has no livebox package\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ info = package_find(lb_pkgname);
+ if (!info)
+ info = package_create(lb_pkgname);
+
+ if (!info) {
+ ret = -EFAULT;
+ } else if (package_is_fault(info)) {
+ ret = -EFAULT;
+ } else if (util_free_space(IMAGE_PATH) < MINIMUM_SPACE) {
+ ErrPrint("Not enough space\n");
+ ret = -ENOSPC;
+ } else {
+ struct inst_info *inst;
+
+ if (period > 0.0f && period < MINIMUM_PERIOD)
+ period = MINIMUM_PERIOD;
+
+ if (!strlen(content))
+ content = DEFAULT_CONTENT;
+
+ inst = instance_create(client, timestamp, lb_pkgname, content, cluster, category, period, width, height);
+ /*!
+ * \note
+ * Using the "inst" without validate its value is at my disposal. ;)
+ */
+ ret = inst ? 0 : -EFAULT;
+ }
+
+ DbgFree(lb_pkgname);
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *client_change_visibility(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ enum livebox_visible_state state;
+ int ret;
+ struct inst_info *inst;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssi", &pkgname, &id, (int *)&state);
+ if (ret != 3) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s] id[%s] state[%d]\n", pid, pkgname, id, state);
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ret = -ENOENT;
+ } else if (package_is_fault(instance_package(inst))) {
+ ret = -EFAULT;
+ } else if (instance_client(inst) != client) {
+ ret = -EPERM;
+ } else {
+ ret = instance_set_visible_state(inst, state);
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_set_period(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, period, ret */
+{
+ struct client_node *client;
+ struct packet *result;
+ const char *pkgname;
+ const char *id;
+ double period;
+ int ret;
+ struct inst_info *inst;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssd", &pkgname, &id, &period);
+ if (ret != 3) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s] id[%s] period[%lf]\n", pid, pkgname, id, period);
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ret = -ENOENT;
+ } else if (package_is_fault(instance_package(inst))) {
+ ret = -EFAULT;
+ } else if (instance_client(inst) != client) {
+ ret = -EPERM;
+ } else {
+ ret = instance_set_period(inst, period);
+ }
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *client_change_group(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, cluster, category, ret */
+{
+ struct client_node *client;
+ struct packet *result;
+ const char *pkgname;
+ const char *id;
+ const char *cluster;
+ const char *category;
+ struct inst_info *inst;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssss", &pkgname, &id, &cluster, &category);
+ if (ret != 4) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s] id[%s] cluster[%s] category[%s]\n", pid, pkgname, id, cluster, category);
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ret = -ENOENT;
+ } else if (package_is_fault(instance_package(inst))) {
+ ret = -EFAULT;
+ } else if (instance_client(inst) != client) {
+ ret = -EPERM;
+ } else {
+ ret = instance_change_group(inst, cluster, category);
+ }
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *client_pd_mouse_enter(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Invalid parameter\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not found\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ // struct packet *packet;
+
+ buffer = instance_pd_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("pd_mouse_enter", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_pd_type(pkg) == PD_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_pd_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+ evas_event_feed_mouse_in(e, timestamp, NULL);
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_pd_mouse_leave(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not found\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ // struct packet *packet;
+
+ buffer = instance_pd_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("pd_mouse_leave", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_pd_type(pkg) == PD_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_pd_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+ evas_event_feed_mouse_out(e, timestamp, NULL);
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_pd_mouse_down(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, id, width, height, timestamp, x, y, ret */
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("(%dx%d) - (%lfx%lf)\n", w, h, x, y);
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not found\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ // struct packet *packet;
+
+ buffer = instance_pd_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("pd_mouse_down", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_pd_type(pkg) == PD_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_pd_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, 1);
+ evas_event_feed_mouse_move(e, x * w, y * h, timestamp, NULL);
+ evas_event_feed_mouse_down(e, 1, EVAS_BUTTON_NONE, timestamp + 0.01f, NULL);
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_pd_mouse_up(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("(%dx%d) - (%lfx%lf)\n", w, h, x, y);
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not exists\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ //struct packet *packet;
+
+ buffer = instance_pd_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("pd_mouse_up", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_pd_type(pkg) == PD_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_pd_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, 0);
+ evas_event_feed_mouse_move(e, x * w, y * h, timestamp, NULL);
+ evas_event_feed_mouse_up(e, 1, EVAS_BUTTON_NONE, timestamp + 0.1f, NULL);
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_pd_mouse_move(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("(%dx%d) - (%lfx%lf)\n", w, h, x, y);
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not exists\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ //struct packet *packet;
+
+ buffer = instance_pd_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * Reuse the packet.
+ packet = packet_create_noack("pd_mouse_move", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_pd_type(pkg) == PD_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_pd_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+ evas_event_feed_mouse_move(e, x * w, y * h, timestamp, NULL);
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_lb_mouse_move(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not exists\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ //struct packet *packet;
+
+ buffer = instance_lb_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("lb_mouse_move", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_lb_type(pkg) == LB_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_lb_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+ evas_event_feed_mouse_move(e, x * w, y * h, timestamp, NULL);
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_lb_mouse_enter(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not exists\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ //struct packet *packet;
+
+ buffer = instance_lb_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("lb_mouse_enter", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_lb_type(pkg) == LB_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_lb_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+ evas_event_feed_mouse_in(e, timestamp, NULL);
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_lb_mouse_leave(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not exists\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ //struct packet *packet;
+
+ buffer = instance_lb_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("lb_mouse_leave", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_lb_type(pkg) == LB_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_lb_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+ evas_event_feed_mouse_out(e, timestamp, NULL);
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_lb_mouse_down(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not exists\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ // struct packet *packet;
+
+ buffer = instance_lb_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("lb_mouse_down", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_lb_type(pkg) == LB_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_lb_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, 1);
+ evas_event_feed_mouse_move(e, x * w, y * h, timestamp, NULL);
+ evas_event_feed_mouse_down(e, 1, EVAS_BUTTON_NONE, timestamp + 0.01f, NULL);
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_lb_mouse_up(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not exists\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ //struct packet *packet;
+
+ buffer = instance_lb_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("lb_mouse_up", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_lb_type(pkg) == LB_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_lb_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, 0);
+ evas_event_feed_mouse_move(e, x * w, y * h, timestamp, NULL);
+ evas_event_feed_mouse_up(e, 1, EVAS_BUTTON_NONE, timestamp + 0.1f, NULL);
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_pd_access_read(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Invalid parameter\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not found\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ // struct packet *packet;
+
+ buffer = instance_pd_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("pd_mouse_enter", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_pd_type(pkg) == PD_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_pd_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+ /*!
+ * \TODO: Push up the ACCESS_READ event
+ */
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_pd_access_read_prev(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Invalid parameter\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not found\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ // struct packet *packet;
+
+ buffer = instance_pd_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("pd_mouse_enter", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_pd_type(pkg) == PD_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_pd_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+ /*!
+ * \TODO: Push up the ACCESS_READ_PREV event
+ */
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_pd_access_read_next(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Invalid parameter\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not found\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ // struct packet *packet;
+
+ buffer = instance_pd_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("pd_mouse_enter", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_pd_type(pkg) == PD_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_pd_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+ /*!
+ * \TODO: Push up the ACCESS_READ_NEXT event
+ */
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_pd_access_activate(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Invalid parameter\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not found\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ // struct packet *packet;
+
+ buffer = instance_pd_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("pd_mouse_enter", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_pd_type(pkg) == PD_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_pd_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+ /*!
+ * \TODO: Push up the ACCESS_READ_ACTIVATE event
+ */
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_pd_key_down(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Invalid parameter\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not found\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ // struct packet *packet;
+
+ buffer = instance_pd_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("pd_mouse_enter", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_pd_type(pkg) == PD_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_pd_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+ /*!
+ * \TODO: Push up the KEY_DOWN event
+ */
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_pause_request(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ double timestamp;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is paused - manually reported\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "d", &timestamp);
+ if (ret != 1) {
+ ErrPrint("Invalid parameter\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (USE_XMONITOR)
+ DbgPrint("XMONITOR enabled. ignore client paused request\n");
+ else
+ xmonitor_pause(client);
+
+out:
+ return NULL;
+}
+
+static struct packet *client_resume_request(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ double timestamp;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is paused - manually reported\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "d", &timestamp);
+ if (ret != 1) {
+ ErrPrint("Invalid parameter\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (USE_XMONITOR)
+ DbgPrint("XMONITOR enabled. ignore client resumed request\n");
+ else
+ xmonitor_resume(client);
+
+out:
+ return NULL;
+}
+
+static struct packet *client_pd_key_up(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Invalid parameter\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not found\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ // struct packet *packet;
+
+ buffer = instance_pd_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("pd_mouse_enter", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_pd_type(pkg) == PD_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_pd_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+ /*!
+ * \TODO: Push up the KEY_UP event
+ */
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_lb_access_read(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not exists\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ //struct packet *packet;
+
+ buffer = instance_lb_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("lb_mouse_leave", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_lb_type(pkg) == LB_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_lb_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+
+ /*!
+ * \TODO: Feed up this ACCESS_READ event
+ */
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_lb_access_read_prev(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not exists\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ //struct packet *packet;
+
+ buffer = instance_lb_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("lb_mouse_leave", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_lb_type(pkg) == LB_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_lb_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+
+ /*!
+ * \TODO: Feed up this ACCESS_READ_PREV event
+ */
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_lb_access_read_next(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not exists\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ //struct packet *packet;
+
+ buffer = instance_lb_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("lb_mouse_leave", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_lb_type(pkg) == LB_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_lb_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+
+ /*!
+ * \TODO: Feed up this ACCESS_READ_NEXT event
+ */
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_lb_access_activate(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not exists\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ //struct packet *packet;
+
+ buffer = instance_lb_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("lb_mouse_leave", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_lb_type(pkg) == LB_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_lb_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+
+ /*!
+ * \TODO: Feed up this ACCESS_ACTIVATE event
+ */
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_lb_key_down(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not exists\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ //struct packet *packet;
+
+ buffer = instance_lb_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("lb_mouse_leave", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_lb_type(pkg) == LB_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_lb_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+
+ /*!
+ * \TODO: Feed up this KEY_DOWN event
+ */
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_lb_key_up(pid_t pid, int handle, const struct packet *packet)
+{
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ int w;
+ int h;
+ double timestamp;
+ double x;
+ double y;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssiiddd", &pkgname, &id, &w, &h, &timestamp, &x, &y);
+ if (ret != 7) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance[%s] is not exists\n", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("Package[%s] info is not exists\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ /*!
+ * \note
+ * If the package is registered as fault module,
+ * slave has not load it, so we don't need to do anything at here!
+ */
+ DbgPrint("Package[%s] is faulted\n", pkgname);
+ ret = -EFAULT;
+ } else if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ struct buffer_info *buffer;
+ struct slave_node *slave;
+ //struct packet *packet;
+
+ buffer = instance_lb_buffer(inst);
+ if (!buffer) {
+ ErrPrint("Instance[%s] has no buffer\n", id);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("Package[%s] has no slave\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ packet = packet_create_noack("lb_mouse_leave", "ssiiddd", pkgname, id, w, h, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet[%s]\n", pkgname);
+ ret = -EFAULT;
+ goto out;
+ }
+ */
+
+ packet_ref((struct packet *)packet);
+ ret = slave_rpc_request_only(slave, pkgname, (struct packet *)packet, 0);
+ } else if (package_lb_type(pkg) == LB_TYPE_SCRIPT) {
+ struct script_info *script;
+ Evas *e;
+
+ script = instance_lb_script(inst);
+ if (!script) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ e = script_handler_evas(script);
+ if (!e) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ script_handler_update_pointer(script, x, y, -1);
+
+ /*!
+ * \TODO: Feed up this KEY_UP event
+ */
+ ret = 0;
+ } else {
+ ErrPrint("Unsupported package\n");
+ ret = -EINVAL;
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static int release_pixmap_cb(struct client_node *client, void *canvas)
+{
+ DbgPrint("Forcely unref the \"buffer\"\n");
+ buffer_handler_pixmap_unref(canvas);
+ return -1; /* Delete this callback */
+}
+
+static struct packet *client_lb_acquire_pixmap(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+{
+ struct packet *result;
+ const char *pkgname;
+ const char *id;
+ struct client_node *client;
+ struct inst_info *inst;
+ int ret;
+ int pixmap = 0;
+ void *buf_ptr;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ goto out;
+ }
+
+ ret = packet_get(packet, "ss", &pkgname, &id);
+ if (ret != 2) {
+ ErrPrint("Parameter is not matched\n");
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Failed to find an instance (%s - %s)\n", pkgname, id);
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s] id[%s]\n", pid, pkgname, id);
+
+ buf_ptr = buffer_handler_pixmap_ref(instance_lb_buffer(inst));
+ if (!buf_ptr) {
+ ErrPrint("Failed to ref pixmap\n");
+ goto out;
+ }
+
+ ret = client_event_callback_add(client, CLIENT_EVENT_DEACTIVATE, release_pixmap_cb, buf_ptr);
+ if (ret < 0) {
+ ErrPrint("Failed to add a new client deactivate callback\n");
+ buffer_handler_pixmap_unref(buf_ptr);
+ pixmap = 0;
+ } else {
+ pixmap = buffer_handler_pixmap(instance_lb_buffer(inst));
+ }
+
+out:
+ result = packet_create_reply(packet, "i", pixmap);
+ if (!result)
+ ErrPrint("Failed to create a reply packet\n");
+
+ return result;
+}
+
+static struct packet *client_lb_release_pixmap(pid_t pid, int handle, const struct packet *packet)
+{
+ const char *pkgname;
+ const char *id;
+ struct client_node *client;
+ struct inst_info *inst;
+ int pixmap;
+ void *buf_ptr;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssi", &pkgname, &id, &pixmap);
+ if (ret != 3) {
+ ErrPrint("Parameter is not matched\n");
+ goto out;
+ }
+ DbgPrint("pid[%d] pkgname[%s] id[%s] Pixmap[0x%X]\n", pid, pkgname, id, pixmap);
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Failed to find an instance (%s - %s)\n", pkgname, id);
+ goto out;
+ }
+
+ buf_ptr = buffer_handler_pixmap_find(pixmap);
+ if (!buf_ptr) {
+ ErrPrint("Failed to find a buf_ptr of 0x%X\n", pixmap);
+ goto out;
+ }
+
+ if (client_event_callback_del(client, CLIENT_EVENT_DEACTIVATE, release_pixmap_cb, buf_ptr) == 0)
+ buffer_handler_pixmap_unref(buf_ptr);
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_pd_acquire_pixmap(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+{
+ struct packet *result;
+ const char *pkgname;
+ const char *id;
+ struct client_node *client;
+ struct inst_info *inst;
+ int ret;
+ int pixmap = 0;
+ void *buf_ptr;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ goto out;
+ }
+
+ ret = packet_get(packet, "ss", &pkgname, &id);
+ if (ret != 2) {
+ ErrPrint("Parameter is not matched\n");
+ goto out;
+ }
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Failed to find an instance (%s - %s)\n", pkgname, id);
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s] id[%s]\n", pid, pkgname, id);
+
+ buf_ptr = buffer_handler_pixmap_ref(instance_pd_buffer(inst));
+ if (!buf_ptr) {
+ ErrPrint("Failed to ref pixmap\n");
+ goto out;
+ }
+
+ ret = client_event_callback_add(client, CLIENT_EVENT_DEACTIVATE, release_pixmap_cb, buf_ptr);
+ if (ret < 0)
+ buffer_handler_pixmap_unref(buf_ptr);
+
+ pixmap = buffer_handler_pixmap(instance_pd_buffer(inst));
+out:
+ result = packet_create_reply(packet, "i", pixmap);
+ if (!result)
+ ErrPrint("Failed to create a reply packet\n");
+
+ return result;
+}
+
+static struct packet *client_pd_release_pixmap(pid_t pid, int handle, const struct packet *packet)
+{
+ const char *pkgname;
+ const char *id;
+ struct client_node *client;
+ struct inst_info *inst;
+ int pixmap;
+ void *buf_ptr;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssi", &pkgname, &id, &pixmap);
+ if (ret != 3) {
+ ErrPrint("Parameter is not matched\n");
+ goto out;
+ }
+ DbgPrint("pid[%d] pkgname[%s] id[%s]\n", pid, pkgname, id);
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Failed to find an instance (%s - %s)\n", pkgname, id);
+ goto out;
+ }
+
+ buf_ptr = buffer_handler_pixmap_find(pixmap);
+ if (!buf_ptr) {
+ ErrPrint("Failed to find a buf_ptr of 0x%X\n", pixmap);
+ goto out;
+ }
+
+ if (client_event_callback_del(client, CLIENT_EVENT_DEACTIVATE, release_pixmap_cb, buf_ptr) == 0)
+ buffer_handler_pixmap_unref(buf_ptr);
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_pinup_changed(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, pinup, ret */
+{
+ struct client_node *client;
+ struct packet *result;
+ const char *pkgname;
+ const char *id;
+ int pinup;
+ int ret;
+ struct inst_info *inst;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ pinup = 0;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssi", &pkgname, &id, &pinup);
+ if (ret != 3) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ pinup = 0;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s] id[%s] pinup[%d]\n", pid, pkgname, id, pinup);
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst)
+ ret = -ENOENT;
+ else if (package_is_fault(instance_package(inst)))
+ ret = -EFAULT;
+ else
+ ret = instance_set_pinup(inst, pinup);
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static Eina_Bool lazy_pd_created_cb(void *data)
+{
+ DbgPrint("Send PD Create event\n");
+ instance_client_pd_created(data, 0);
+
+ instance_unref(data);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool lazy_pd_destroyed_cb(void *data)
+{
+ DbgPrint("Send PD Destroy event\n");
+ instance_client_pd_destroyed(data, 0);
+
+ instance_unref(data);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static struct packet *client_pd_move(pid_t pid, int handle, const struct packet *packet) /* pkgname, id, x, y */
+{
+ struct client_node *client;
+ struct inst_info *inst;
+ const char *pkgname;
+ const char *id;
+ double x = 0.0f;
+ double y = 0.0f;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssdd", &pkgname, &id, &x, &y);
+ if (ret != 4) {
+ ErrPrint("Parameter is not correct\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s] id[%s] %lfx%lf\n", pid, pkgname, id, x, y);
+
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst)
+ ret = -ENOENT;
+ else if (package_is_fault(instance_package(inst)))
+ ret = -EFAULT;
+ else if (package_pd_type(instance_package(inst)) == PD_TYPE_BUFFER) {
+ instance_slave_set_pd_pos(inst, x, y);
+ ret = instance_signal_emit(inst,
+ "pd,move", util_uri_to_path(instance_id(inst)),
+ 0.0, 0.0, 0.0, 0.0, x, y, 0);
+ } else if (package_pd_type(instance_package(inst)) == PD_TYPE_SCRIPT) {
+ instance_slave_set_pd_pos(inst, x, y);
+ script_handler_update_pointer(instance_pd_script(inst), x, y, 0);
+ ret = instance_signal_emit(inst,
+ "pd,move", util_uri_to_path(instance_id(inst)),
+ 0.0, 0.0, 0.0, 0.0, x, y, 0);
+ } else {
+ ErrPrint("Invalid PD type\n");
+ ret = -EINVAL;
+ }
+out:
+ DbgPrint("Update PD position: %lfx%lf (%d)\n", x, y, ret);
+ return NULL;
+}
+
+static struct packet *client_create_pd(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, ret */
+{
+ struct client_node *client;
+ struct packet *result;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ struct inst_info *inst;
+ double x;
+ double y;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssdd", &pkgname, &id, &x, &y);
+ if (ret != 4) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s] id[%s]\n", pid, pkgname, id);
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst)
+ ret = -ENOENT;
+ else if (package_is_fault(instance_package(inst)))
+ ret = -EFAULT;
+ else if (util_free_space(IMAGE_PATH) < MINIMUM_SPACE)
+ ret = -ENOSPC;
+ else if (package_pd_type(instance_package(inst)) == PD_TYPE_BUFFER) {
+ instance_slave_set_pd_pos(inst, x, y);
+ ret = instance_slave_open_pd(inst, client);
+ ret = instance_signal_emit(inst,
+ "pd,show", util_uri_to_path(instance_id(inst)),
+ 0.0, 0.0, 0.0, 0.0, x, y, 0);
+ /*!
+ * \note
+ * PD craeted event will be send by the acquire_buffer function.
+ * Because the slave will make request the acquire_buffer to
+ * render the PD
+ *
+ * instance_client_pd_created(inst);
+ */
+ } else if (package_pd_type(instance_package(inst)) == PD_TYPE_SCRIPT) {
+ /*!
+ * \note
+ * ret value should be cared but in this case,
+ * we ignore this for this moment, so we have to handle this error later.
+ *
+ * if ret is less than 0, the slave has some problem.
+ * but the script mode doesn't need slave for rendering default view of PD
+ * so we can hanle it later.
+ */
+ instance_slave_set_pd_pos(inst, x, y);
+ script_handler_update_pointer(instance_pd_script(inst), x, y, 0);
+ ret = instance_slave_open_pd(inst, client);
+ ret = script_handler_load(instance_pd_script(inst), 1);
+
+ /*!
+ * \note
+ * Send the PD created event to the clients,
+ */
+ if (ret == 0) {
+ /*!
+ * \note
+ * But the created event has to be send afte return
+ * from this function or the viewer couldn't care
+ * the event correctly.
+ */
+ inst = instance_ref(inst); /* To guarantee the inst */
+ if (!ecore_timer_add(DELAY_TIME, lazy_pd_created_cb, inst))
+ instance_unref(inst);
+ } else {
+ instance_client_pd_created(inst, ret);
+ }
+ } else {
+ ErrPrint("Invalid PD TYPE\n");
+ ret = -EINVAL;
+ }
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *client_destroy_pd(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, filename, ret */
+{
+ struct client_node *client;
+ struct packet *result;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ struct inst_info *inst;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ss", &pkgname, &id);
+ if (ret != 2) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s] id[%s]\n", pid, pkgname, id);
+
+ /*!
+ * \NOTE:
+ * Trust the package name which are sent by the client.
+ * The package has to be a livebox package name.
+ */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst)
+ ret = -ENOENT;
+ else if (package_is_fault(instance_package(inst)))
+ ret = -EFAULT;
+ else if (package_pd_type(instance_package(inst)) == PD_TYPE_BUFFER) {
+ ret = instance_signal_emit(inst,
+ "pd,hide", util_uri_to_path(instance_id(inst)),
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0);
+ ret = instance_slave_close_pd(inst, client);
+
+ /*!
+ * \note
+ * release_buffer will be called by the slave after this.
+ * Then it will send the "pd_destroyed" event to the client
+ *
+ * instance_client_pd_destroyed(inst);
+ */
+
+ } else if (package_pd_type(instance_package(inst)) == PD_TYPE_SCRIPT) {
+ ret = script_handler_unload(instance_pd_script(inst), 1);
+ ret = instance_slave_close_pd(inst, client);
+
+ /*!
+ * \note
+ * Send the destroyed PD event to the client
+ */
+ if (ret == 0) {
+ inst = instance_ref(inst);
+ if (!ecore_timer_add(DELAY_TIME, lazy_pd_destroyed_cb, inst))
+ instance_unref(inst);
+ }
+ } else {
+ ErrPrint("Invalid PD TYPE\n");
+ ret = -EINVAL;
+ }
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *client_activate_package(pid_t pid, int handle, const struct packet *packet) /* pid, pkgname, ret */
+{
+ struct client_node *client;
+ struct packet *result;
+ const char *pkgname;
+ int ret;
+ struct pkg_info *info;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ pkgname = "";
+ goto out;
+ }
+
+ ret = packet_get(packet, "s", &pkgname);
+ if (ret != 1) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ pkgname = "";
+ goto out;
+ }
+
+ DbgPrint("pid[%d] pkgname[%s]\n", pid, pkgname);
+
+ /*!
+ * \NOTE:
+ * Validate the livebox package name.
+ */
+ if (!package_is_lb_pkgname(pkgname)) {
+ ErrPrint("%s is not a valid livebox package\n", pkgname);
+ pkgname = "";
+ ret = -EINVAL;
+ goto out;
+ }
+
+ info = package_find(pkgname);
+ if (!info)
+ ret = -ENOENT;
+ else
+ ret = package_clear_fault(info);
+
+out:
+ result = packet_create_reply(packet, "is", ret, pkgname);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *client_subscribed(pid_t pid, int handle, const struct packet *packet)
+{
+ const char *cluster;
+ const char *category;
+ struct client_node *client;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ss", &cluster, &category);
+ if (ret != 2) {
+ ErrPrint("Invalid argument\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("[%d] cluster[%s] category[%s]\n", pid, cluster, category);
+ if (!strlen(cluster) || !strcasecmp(cluster, DEFAULT_CLUSTER)) {
+ ErrPrint("Invalid cluster name\n");
+ goto out;
+ }
+
+ /*!
+ * \todo
+ * SUBSCRIBE cluster & sub-cluster for a client.
+ */
+ ret = client_subscribe(client, cluster, category);
+ if (ret == 0)
+ package_alter_instances_to_client(client, ALTER_CREATE);
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_delete_cluster(pid_t pid, int handle, const struct packet *packet)
+{
+ const char *cluster;
+ struct client_node *client;
+ struct packet *result;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "s", &cluster);
+ if (ret != 1) {
+ ErrPrint("Invalid parameters\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] cluster[%s]\n", pid, cluster);
+
+ if (!strlen(cluster) || !strcasecmp(cluster, DEFAULT_CLUSTER)) {
+ ErrPrint("Invalid cluster: %s\n", cluster);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \todo
+ */
+ ret = -ENOSYS;
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+ return result;
+}
+
+static inline int update_pkg_cb(struct category *category, const char *pkgname)
+{
+ const char *c_name;
+ const char *s_name;
+
+ c_name = group_cluster_name_by_category(category);
+ s_name = group_category_name(category);
+
+ if (!c_name || !s_name || !pkgname) {
+ ErrPrint("Name is not valid\n");
+ return EXIT_FAILURE;
+ }
+
+ DbgPrint("Send refresh request: %s (%s/%s)\n", pkgname, c_name, s_name);
+ slave_rpc_request_update(pkgname, "", c_name, s_name);
+
+ /* Just try to create a new package */
+ if (util_free_space(IMAGE_PATH) > MINIMUM_SPACE) {
+ double timestamp;
+ struct inst_info *inst;
+
+ timestamp = util_timestamp();
+ /*!
+ * \NOTE
+ * Don't need to check the subscribed clients.
+ * Because this callback is called by the requests of clients.
+ * It means. some clients wants to handle this instances ;)
+ */
+ inst = instance_create(NULL, timestamp, pkgname, DEFAULT_CONTENT, c_name, s_name, DEFAULT_PERIOD, 0, 0);
+ if (!inst)
+ ErrPrint("Failed to create a new instance\n");
+ } else {
+ ErrPrint("Not enough space\n");
+ }
+ return EXIT_SUCCESS;
+}
+
+static struct packet *client_update(pid_t pid, int handle, const struct packet *packet)
+{
+ struct inst_info *inst;
+ struct client_node *client;
+ const char *pkgname;
+ const char *id;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Cilent %d is not exists\n", pid);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ss", &pkgname, &id);
+ if (ret != 2) {
+ ErrPrint("Invalid argument\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ret = -ENOENT;
+ } else if (package_is_fault(instance_package(inst))) {
+ ret = -EFAULT;
+ } else if (instance_client(inst) != client) {
+ ret = -EPERM;
+ } else {
+ slave_rpc_request_update(pkgname, id, instance_cluster(inst), instance_category(inst));
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_refresh_group(pid_t pid, int handle, const struct packet *packet)
+{
+ const char *cluster_id;
+ const char *category_id;
+ struct client_node *client;
+ int ret;
+ struct cluster *cluster;
+ struct category *category;
+ struct context_info *info;
+ Eina_List *info_list;
+ Eina_List *l;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Cilent %d is not exists\n", pid);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ss", &cluster_id, &category_id);
+ if (ret != 2) {
+ ErrPrint("Invalid parameter\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("[%d] cluster[%s] category[%s]\n", pid, cluster_id, category_id);
+
+ if (!strlen(cluster_id) || !strcasecmp(cluster_id, DEFAULT_CLUSTER)) {
+ ErrPrint("Invalid cluster name: %s\n", cluster_id);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ cluster = group_find_cluster(cluster_id);
+ if (!cluster) {
+ ErrPrint("Cluster [%s] is not registered\n", cluster_id);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ category = group_find_category(cluster, category_id);
+ if (!category) {
+ ErrPrint("Category [%s] is not registered\n", category_id);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ info_list = group_context_info_list(category);
+ EINA_LIST_FOREACH(info_list, l, info) {
+ update_pkg_cb(category, group_pkgname_from_context_info(info));
+ }
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *client_delete_category(pid_t pid, int handle, const struct packet *packet)
+{
+ const char *cluster;
+ const char *category;
+ struct client_node *client;
+ struct packet *result;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ss", &cluster, &category);
+ if (ret != 2) {
+ ErrPrint("Invalid paramenters\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("pid[%d] cluster[%s] category[%s]\n", pid, cluster, category);
+ if (!strlen(cluster) || !strcasecmp(cluster, DEFAULT_CLUSTER)) {
+ ErrPrint("Invalid cluster: %s\n", cluster);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*!
+ * \todo
+ */
+ ret = -ENOSYS;
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+ return result;
+}
+
+static struct packet *client_unsubscribed(pid_t pid, int handle, const struct packet *packet)
+{
+ const char *cluster;
+ const char *category;
+ struct client_node *client;
+ int ret;
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ ErrPrint("Client %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ss", &cluster, &category);
+ if (ret != 2) {
+ ErrPrint("Invalid argument\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("[%d] cluster[%s] category[%s]\n", pid, cluster, category);
+
+ if (!strlen(cluster) || !strcasecmp(cluster, DEFAULT_CLUSTER)) {
+ ErrPrint("Invalid cluster name: %s\n", cluster);
+ goto out;
+ }
+
+ /*!
+ * \todo
+ * UNSUBSCRIBE cluster & sub-cluster for a client.
+ */
+ ret = client_unsubscribe(client, cluster, category);
+ if (ret == 0)
+ package_alter_instances_to_client(client, ALTER_DESTROY);
+
+out:
+ /*! \note No reply packet */
+ return NULL;
+}
+
+static struct packet *slave_hello(pid_t pid, int handle, const struct packet *packet) /* slave_name, ret */
+{
+ struct slave_node *slave;
+ const char *slavename;
+ int ret;
+
+ ret = packet_get(packet, "s", &slavename);
+ if (ret != 1) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DbgPrint("New slave[%s](%d) is arrived\n", slavename, pid);
+
+ slave = slave_find_by_pid(pid);
+ if (!slave) {
+ if (DEBUG_MODE) {
+ char pkgname[pathconf("/", _PC_PATH_MAX)];
+ const char *abi;
+
+ if (aul_app_get_pkgname_bypid(pid, pkgname, sizeof(pkgname)) != AUL_R_OK) {
+ ErrPrint("pid[%d] is not authroized provider package, try to find it using its name[%s]\n", pid, slavename);
+ slave = slave_find_by_name(slavename);
+ pkgname[0] = '\0'; /* Reset the pkgname */
+ } else {
+ slave = slave_find_by_pkgname(pkgname);
+ }
+
+ if (!slave) {
+ abi = abi_find_by_pkgname(pkgname);
+ if (!abi) {
+ abi = DEFAULT_ABI;
+ DbgPrint("Slave pkgname is invalid, ABI is replaced with '%s'(default)\n", abi);
+ }
+
+ slave = slave_create(slavename, 1, abi, pkgname);
+ if (!slave) {
+ ErrPrint("Failed to create a new slave for %s\n", slavename);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ DbgPrint("New slave is created\n");
+ } else {
+ DbgPrint("Registered slave is replaced with this new one\n");
+ abi = slave_abi(slave);
+ }
+
+ slave_set_pid(slave, pid);
+ DbgPrint("Provider is forcely activated, pkgname(%s), abi(%s), slavename(%s)\n", pkgname, abi, slavename);
+ } else {
+ ErrPrint("Slave[%d] is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+ }
+
+ /*!
+ * \note
+ * After updating handle,
+ * slave activated callback will be called.
+ */
+ slave_rpc_update_handle(slave, handle);
+
+out:
+ return NULL;
+}
+
+static struct packet *slave_ping(pid_t pid, int handle, const struct packet *packet) /* slave_name, ret */
+{
+ struct slave_node *slave;
+ const char *slavename;
+ int ret;
+
+ slave = slave_find_by_pid(pid);
+ if (!slave) {
+ ErrPrint("Slave %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "s", &slavename);
+ if (ret != 1) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ slave_rpc_ping(slave);
+
+out:
+ return NULL;
+}
+
+static struct packet *slave_faulted(pid_t pid, int handle, const struct packet *packet)
+{
+ struct slave_node *slave;
+ struct inst_info *inst;
+ const char *slavename;
+ const char *pkgname;
+ const char *id;
+ const char *func;
+ int ret;
+
+ slave = slave_find_by_pid(pid);
+ if (!slave) {
+ ErrPrint("Slave %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssss", &slavename, &pkgname, &id, &func);
+ if (ret != 4) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = fault_info_set(slave, pkgname, id, func);
+ DbgPrint("Slave Faulted: %s (%d)\n", slavename, ret);
+
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ DbgPrint("There is a no such instance(%s)\n", id);
+ ret = -ENOENT;
+ } else if (instance_state(inst) == INST_DESTROYED) {
+ ErrPrint("Instance(%s) is already destroyed\n", id);
+ ret = -EINVAL;
+ } else {
+ DbgPrint("Destroy instance(%s)\n", id);
+ ret = instance_destroy(inst);
+ }
+
+out:
+ return NULL;
+}
+
+static struct packet *slave_call(pid_t pid, int handle, const struct packet *packet) /* slave_name, pkgname, filename, function, ret */
+{
+ struct slave_node *slave;
+ const char *slavename;
+ const char *pkgname;
+ const char *id;
+ const char *func;
+ int ret;
+
+ slave = slave_find_by_pid(pid);
+ if (!slave) {
+ ErrPrint("Slave %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssss", &slavename, &pkgname, &id, &func);
+ if (ret != 4) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = fault_func_call(slave, pkgname, id, func);
+ slave_give_more_ttl(slave);
+
+out:
+ return NULL;
+}
+
+static struct packet *slave_ret(pid_t pid, int handle, const struct packet *packet) /* slave_name, pkgname, filename, function, ret */
+{
+ struct slave_node *slave;
+ const char *slavename;
+ const char *pkgname;
+ const char *id;
+ const char *func;
+ int ret;
+
+ slave = slave_find_by_pid(pid);
+ if (!slave) {
+ ErrPrint("Slave %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssss", &slavename, &pkgname, &id, &func);
+ if (ret != 4) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = fault_func_ret(slave, pkgname, id, func);
+ slave_give_more_ttl(slave);
+
+out:
+ return NULL;
+}
+
+static struct packet *slave_updated(pid_t pid, int handle, const struct packet *packet) /* slave_name, pkgname, filename, width, height, priority, ret */
+{
+ struct slave_node *slave;
+ const char *slavename;
+ const char *pkgname;
+ const char *id;
+ const char *content_info;
+ const char *title;
+ int w;
+ int h;
+ double priority;
+ int ret;
+ struct inst_info *inst;
+
+ slave = slave_find_by_pid(pid);
+ if (!slave) {
+ ErrPrint("Slave %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "sssiidss", &slavename, &pkgname, &id,
+ &w, &h, &priority,
+ &content_info, &title);
+ if (ret != 8) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ret = -ENOENT;
+ } else if (package_is_fault(instance_package(inst))) {
+ ErrPrint("Faulted instance cannot make any event.\n");
+ ret = -EFAULT;
+ } else if (instance_state(inst) == INST_DESTROYED) {
+ ErrPrint("Instance is already destroyed\n");
+ ret = -EINVAL;
+ } else {
+ char *filename;
+ int resized;
+
+ resized = (instance_lb_width(inst) != w) || (instance_lb_height(inst) != h);
+ instance_set_lb_info(inst, w, h, priority, content_info, title);
+
+ switch (package_lb_type(instance_package(inst))) {
+ case LB_TYPE_SCRIPT:
+ script_handler_resize(instance_lb_script(inst), w, h);
+
+ filename = util_get_file_kept_in_safe(id);
+ if (filename) {
+ ret = script_handler_parse_desc(pkgname, id,
+ filename, 0);
+ DbgFree(filename);
+ } else {
+ ret = script_handler_parse_desc(pkgname, id,
+ util_uri_to_path(id), 0);
+ }
+ break;
+ case LB_TYPE_BUFFER:
+ default:
+ /*!
+ * \check
+ * text format (inst)
+ */
+ if (resized)
+ instance_send_resized_event(inst, IS_LB, w, h, 0);
+ instance_lb_updated_by_instance(inst);
+ ret = 0;
+ break;
+ }
+
+ slave_give_more_ttl(slave);
+ }
+
+out:
+ return NULL;
+}
+
+static struct packet *slave_desc_updated(pid_t pid, int handle, const struct packet *packet) /* slave_name, pkgname, filename, decsfile, ret */
+{
+ struct slave_node *slave;
+ const char *slavename;
+ const char *pkgname;
+ const char *id;
+ const char *descfile;
+ int ret;
+ struct inst_info *inst;
+
+ slave = slave_find_by_pid(pid);
+ if (!slave) {
+ ErrPrint("Slave %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "ssss", &slavename, &pkgname, &id, &descfile);
+ if (ret != 4) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ret = -ENOENT;
+ } else if (package_is_fault(instance_package(inst))) {
+ ErrPrint("Faulted package cannot make event\n");
+ ret = -EFAULT;
+ } else if (instance_state(inst) == INST_DESTROYED) {
+ ErrPrint("Instance is already destroyed\n");
+ ret = -EINVAL;
+ } else {
+ switch (package_pd_type(instance_package(inst))) {
+ case PD_TYPE_SCRIPT:
+ DbgPrint("Script (%s)\n", id);
+ if (script_handler_is_loaded(instance_pd_script(inst))) {
+ ret = script_handler_parse_desc(pkgname, id,
+ descfile, 1);
+ }
+ break;
+ case PD_TYPE_TEXT:
+ instance_set_pd_info(inst, 0, 0);
+ case PD_TYPE_BUFFER:
+ instance_pd_updated(pkgname, id, descfile);
+ ret = 0;
+ break;
+ default:
+ DbgPrint("Ignore updated DESC(%s - %s - %s)\n",
+ pkgname, id, descfile);
+ ret = 0;
+ break;
+ }
+ }
+
+out:
+ return NULL;
+}
+
+static struct packet *slave_deleted(pid_t pid, int handle, const struct packet *packet) /* slave_name, pkgname, id, ret */
+{
+ struct slave_node *slave;
+ const char *slavename;
+ const char *pkgname;
+ const char *id;
+ int ret;
+ struct inst_info *inst;
+
+ slave = slave_find_by_pid(pid);
+ if (!slave) {
+ ErrPrint("Slave %d is not exists\n", pid);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "sss", &slavename, &pkgname, &id);
+ if (ret != 3) {
+ ErrPrint("Parameter is not matched\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst)
+ ret = -ENOENT;
+ else if (package_is_fault(instance_package(inst)))
+ ret = -EFAULT;
+ else
+ ret = instance_destroyed(inst);
+
+out:
+ return NULL;
+}
+
+/*!
+ * \note for the BUFFER Type slave
+ */
+static struct packet *slave_acquire_buffer(pid_t pid, int handle, const struct packet *packet) /* type, id, w, h, size */
+{
+ enum target_type target;
+ const char *slavename;
+ const char *pkgname;
+ const char *id;
+ int w;
+ int h;
+ int pixel_size;
+ struct packet *result;
+ struct slave_node *slave;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+ int ret;
+
+ slave = slave_find_by_pid(pid);
+ if (!slave) {
+ ErrPrint("Failed to find a slave\n");
+ id = "";
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = packet_get(packet, "isssiii", &target, &slavename, &pkgname, &id, &w, &h, &pixel_size);
+ if (ret != 7) {
+ ErrPrint("Invalid argument\n");
+ id = "";
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (util_free_space(IMAGE_PATH) < MINIMUM_SPACE) {
+ DbgPrint("No space\n");
+ ret = -ENOSPC;
+ id = "";
+ goto out;
+ }
+
+ /* TODO: */
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ DbgPrint("Package[%s] Id[%s] is not found\n", pkgname, id);
+ ret = -EINVAL;
+ id = "";
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ id = "";
+ ret = -EINVAL;
+ if (target == TYPE_LB) {
+ if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ struct buffer_info *info;
+
+ info = instance_lb_buffer(inst);
+ if (!info) {
+ if (!instance_create_lb_buffer(inst)) {
+ ErrPrint("Failed to create a LB buffer\n");
+ } else {
+ info = instance_lb_buffer(inst);
+ if (!info) {
+ ErrPrint("LB buffer is not valid\n");
+ ret = -EINVAL;
+ id = "";
+ goto out;
+ }
+ }
+ }
+
+ ret = buffer_handler_resize(info, w, h);
+ DbgPrint("Buffer resize returns %d\n", ret);
+
+ ret = buffer_handler_load(info);
+ if (ret == 0) {
+ int resized;
+ resized = (instance_lb_width(inst) != w) || (instance_lb_height(inst) != h);
+ instance_set_lb_info(inst, w, h, PRIORITY_NO_CHANGE, CONTENT_NO_CHANGE, TITLE_NO_CHANGE);
+ id = buffer_handler_id(info);
+ if (resized)
+ instance_send_resized_event(inst, IS_LB, w, h, 0);
+ DbgPrint("Buffer handler ID: %s\n", id);
+ } else {
+ DbgPrint("Failed to load a buffer(%d)\n", ret);
+ }
+ }
+ } else if (target == TYPE_PD) {
+ if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ struct buffer_info *info;
+
+ DbgPrint("Slave acquire buffer for PD\n");
+
+ info = instance_pd_buffer(inst);
+ if (!info) {
+ if (!instance_create_pd_buffer(inst)) {
+ ErrPrint("Failed to create a PD buffer\n");
+ } else {
+ info = instance_pd_buffer(inst);
+ if (!info) {
+ ErrPrint("PD buffer is not valid\n");
+ ret = -EINVAL;
+ id = "";
+ instance_client_pd_created(inst, ret);
+ goto out;
+ }
+ }
+ }
+
+ ret = buffer_handler_resize(info, w, h);
+ DbgPrint("Buffer resize returns %d\n", ret);
+
+ ret = buffer_handler_load(info);
+ if (ret == 0) {
+ int resized;
+ resized = (instance_pd_width(inst) != w) || (instance_pd_height(inst) != h);
+ instance_set_pd_info(inst, w, h);
+ id = buffer_handler_id(info);
+ if (resized)
+ instance_send_resized_event(inst, IS_PD, w, h, 0);
+ DbgPrint("Buffer handler ID: %s\n", id);
+ } else {
+ DbgPrint("Failed to load a buffer (%d)\n", ret);
+ }
+
+ /*!
+ * Send the PD created event to the client
+ */
+ instance_client_pd_created(inst, ret);
+ }
+ }
+
+out:
+ result = packet_create_reply(packet, "is", ret, id);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *slave_resize_buffer(pid_t pid, int handle, const struct packet *packet)
+{
+ struct slave_node *slave;
+ struct packet *result;
+ enum target_type type;
+ const char *slavename;
+ const char *pkgname;
+ const char *id;
+ int w;
+ int h;
+ struct inst_info *inst;
+ const struct pkg_info *pkg;
+ int ret;
+
+ slave = slave_find_by_pid(pid);
+ if (!slave) {
+ ErrPrint("Failed to find a slave\n");
+ ret = -ENOENT;
+ id = "";
+ goto out;
+ }
+
+ if (util_free_space(IMAGE_PATH) < MINIMUM_SPACE) {
+ ErrPrint("Not enough space\n");
+ ret = -ENOSPC;
+ id = "";
+ goto out;
+ }
+
+ ret = packet_get(packet, "isssii", &type, &slavename, &pkgname, &id, &w, &h);
+ if (ret != 6) {
+ ErrPrint("Invalid argument\n");
+ ret = -EINVAL;
+ id = "";
+ goto out;
+ }
+
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ DbgPrint("Instance is not found[%s] [%s]\n", pkgname, id);
+ ret = -ENOENT;
+ id = "";
+ goto out;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ /*!
+ * \note
+ * THIS statement should not be entered.
+ */
+ ErrPrint("PACKAGE INFORMATION IS NOT VALID\n");
+ ret = -EFAULT;
+ id = "";
+ goto out;
+ }
+
+ ret = -EINVAL;
+ /*!
+ * \note
+ * Reset "id", It will be re-used from here
+ */
+ id = "";
+ if (type == TYPE_LB) {
+ if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ struct buffer_info *info;
+
+ info = instance_lb_buffer(inst);
+ if (info) {
+ ret = buffer_handler_resize(info, w, h);
+ /*!
+ * \note
+ * id is resued for newly assigned ID
+ */
+ if (!ret) {
+ int resized;
+
+ id = buffer_handler_id(info);
+ resized = (instance_lb_width(inst) != w) || (instance_lb_height(inst) != h);
+ instance_set_lb_info(inst, w, h, PRIORITY_NO_CHANGE, CONTENT_NO_CHANGE, TITLE_NO_CHANGE);
+ if (resized)
+ instance_send_resized_event(inst, IS_LB, w, h, 0);
+ }
+ }
+ }
+ } else if (type == TYPE_PD) {
+ if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ struct buffer_info *info;
+
+ info = instance_pd_buffer(inst);
+ if (info) {
+ ret = buffer_handler_resize(info, w, h);
+ /*!
+ * \note
+ * id is resued for newly assigned ID
+ */
+ if (!ret) {
+ int resized;
+ id = buffer_handler_id(info);
+ resized = (instance_pd_width(inst) != w) || (instance_pd_height(inst) != h);
+ instance_set_pd_info(inst, w, h);
+ if (resized)
+ instance_send_resized_event(inst, IS_PD, w, h, 0);
+ }
+ }
+ }
+ }
+
+out:
+ result = packet_create_reply(packet, "is", ret, id);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *slave_release_buffer(pid_t pid, int handle, const struct packet *packet)
+{
+ enum target_type type;
+ const char *slavename;
+ const char *pkgname;
+ const char *id;
+ struct packet *result;
+ struct slave_node *slave;
+ struct inst_info *inst;
+ int ret;
+
+ slave = slave_find_by_pid(pid);
+ if (!slave) {
+ ErrPrint("Failed to find a slave\n");
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (packet_get(packet, "isss", &type, &slavename, &pkgname, &id) != 4) {
+ ErrPrint("Inavlid argument\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ ErrPrint("Instance is not found [%s - %s]\n", pkgname, id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = -EINVAL;
+ if (type == TYPE_LB) {
+ struct buffer_info *info;
+
+ info = instance_lb_buffer(inst);
+ ret = buffer_handler_unload(info);
+ } else if (type == TYPE_PD) {
+ struct buffer_info *info;
+
+ DbgPrint("Slave release buffer for PD\n");
+
+ info = instance_pd_buffer(inst);
+ ret = buffer_handler_unload(info);
+
+ /*!
+ * \note
+ * Send the PD destroyed event to the client
+ */
+ instance_client_pd_destroyed(inst, ret);
+ }
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *service_change_period(pid_t pid, int handle, const struct packet *packet)
+{
+ struct inst_info *inst;
+ struct packet *result;
+ const char *pkgname;
+ const char *id;
+ double period;
+ int ret;
+
+ ret = packet_get(packet, "ssd", &pkgname, &id, &period);
+ if (ret != 3) {
+ ErrPrint("Invalid packet\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!strlen(id)) {
+ struct pkg_info *pkg;
+
+ pkg = package_find(pkgname);
+ if (!pkg) {
+ ret = -ENOENT;
+ } else if (package_is_fault(pkg)) {
+ ret = -EFAULT;
+ } else {
+ Eina_List *inst_list;
+ Eina_List *l;
+
+ inst_list = package_instance_list(pkg);
+ EINA_LIST_FOREACH(inst_list, l, inst) {
+ ret = instance_set_period(inst, period);
+ if (ret < 0)
+ DbgPrint("Failed to change the period of %s to (%lf)\n", instance_id(inst), period);
+ }
+ }
+ } else {
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst)
+ ret = -ENOENT;
+ else if (package_is_fault(instance_package(inst)))
+ ret = -EFAULT;
+ else
+ ret = instance_set_period(inst, period);
+ }
+
+ DbgPrint("Change the update period: %s(%s), %lf : %d\n", pkgname, id, period, ret);
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *service_update(pid_t pid, int handle, const struct packet *packet)
+{
+ struct pkg_info *pkg;
+ struct packet *result;
+ const char *pkgname;
+ const char *id;
+ const char *cluster;
+ const char *category;
+ char *lb_pkgname;
+ int ret;
+
+ ret = packet_get(packet, "ssss", &pkgname, &id, &cluster, &category);
+ if (ret != 4) {
+ ErrPrint("Invalid Packet\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ lb_pkgname = package_lb_pkgname(pkgname);
+ if (!lb_pkgname) {
+ ErrPrint("Invalid package %s\n", pkgname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pkg = package_find(lb_pkgname);
+ if (!pkg) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (package_is_fault(pkg)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ /*!
+ * \TODO
+ * Validate the update requstor.
+ */
+ slave_rpc_request_update(lb_pkgname, id, cluster, category);
+ DbgFree(lb_pkgname);
+ ret = 0;
+
+out:
+ result = packet_create_reply(packet, "i", ret);
+ if (!result)
+ ErrPrint("Failed to create a packet\n");
+
+ return result;
+}
+
+static struct packet *liveinfo_hello(pid_t pid, int handle, const struct packet *packet)
+{
+ struct liveinfo *info;
+ struct packet *result;
+ int ret;
+ const char *fifo_name;
+ double timestamp;
+
+ DbgPrint("Request arrived from %d\n", pid);
+
+ if (packet_get(packet, "d", &timestamp) != 1) {
+ ErrPrint("Invalid packet\n");
+ fifo_name = "";
+ ret = -EINVAL;
+ goto out;
+ }
+
+ info = liveinfo_create(pid, handle);
+ if (!info) {
+ ErrPrint("Failed to create a liveinfo object\n");
+ fifo_name = "";
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = 0;
+ fifo_name = liveinfo_filename(info);
+ DbgPrint("FIFO Created: %s (Serve for %d)\n", fifo_name, pid);
+
+out:
+ result = packet_create_reply(packet, "si", fifo_name, ret);
+ if (!result)
+ ErrPrint("Failed to create a result packet\n");
+
+ return result;
+}
+
+static struct packet *liveinfo_slave_list(pid_t pid, int handle, const struct packet *packet)
+{
+ Eina_List *l;
+ Eina_List *list;
+ struct liveinfo *info;
+ struct slave_node *slave;
+ FILE *fp;
+ double timestamp;
+
+ if (packet_get(packet, "d", &timestamp) != 1) {
+ ErrPrint("Invalid argument\n");
+ goto out;
+ }
+
+ info = liveinfo_find_by_pid(pid);
+ if (!info) {
+ ErrPrint("Invalid request\n");
+ goto out;
+ }
+
+ liveinfo_open_fifo(info);
+ fp = liveinfo_fifo(info);
+ if (!fp) {
+ liveinfo_close_fifo(info);
+ goto out;
+ }
+
+ list = (Eina_List *)slave_list();
+ EINA_LIST_FOREACH(list, l, slave) {
+ fprintf(fp, "%d %s %s %s %d %d %d %s %d %d %lf\n",
+ slave_pid(slave),
+ slave_name(slave),
+ slave_pkgname(slave),
+ slave_abi(slave),
+ slave_is_secured(slave),
+ slave_refcnt(slave),
+ slave_fault_count(slave),
+ slave_state_string(slave),
+ slave_loaded_instance(slave),
+ slave_loaded_package(slave),
+ slave_ttl(slave)
+ );
+ }
+
+ fprintf(fp, "EOD\n");
+ liveinfo_close_fifo(info);
+out:
+ return NULL;
+}
+
+static inline const char *visible_state_string(enum livebox_visible_state state)
+{
+ switch (state) {
+ case LB_SHOW:
+ return "Show";
+ case LB_HIDE:
+ return "Hide";
+ case LB_HIDE_WITH_PAUSE:
+ return "Paused";
+ default:
+ break;
+ }
+
+ return "Unknown";
+}
+
+static struct packet *liveinfo_inst_list(pid_t pid, int handle, const struct packet *packet)
+{
+ const char *pkgname;
+ struct liveinfo *info;
+ struct pkg_info *pkg;
+ Eina_List *l;
+ Eina_List *inst_list;
+ struct inst_info *inst;
+ FILE *fp;
+
+ if (packet_get(packet, "s", &pkgname) != 1) {
+ ErrPrint("Invalid argument\n");
+ goto out;
+ }
+
+ info = liveinfo_find_by_pid(pid);
+ if (!info) {
+ ErrPrint("Invalid request\n");
+ goto out;
+ }
+
+ liveinfo_open_fifo(info);
+ fp = liveinfo_fifo(info);
+ if (!fp) {
+ ErrPrint("Invalid fp\n");
+ liveinfo_close_fifo(info);
+ goto out;
+ }
+
+ if (!package_is_lb_pkgname(pkgname)) {
+ ErrPrint("Invalid package name\n");
+ goto close_out;
+ }
+
+ pkg = package_find(pkgname);
+ if (!pkg) {
+ ErrPrint("Package is not exists\n");
+ goto close_out;
+ }
+
+ inst_list = package_instance_list(pkg);
+ EINA_LIST_FOREACH(inst_list, l, inst) {
+ fprintf(fp, "%s %s %s %lf %s %d %d\n",
+ instance_id(inst),
+ instance_cluster(inst),
+ instance_category(inst),
+ instance_period(inst),
+ visible_state_string(instance_visible_state(inst)),
+ instance_lb_width(inst),
+ instance_lb_height(inst));
+ }
+
+close_out:
+ fprintf(fp, "EOD\n");
+ liveinfo_close_fifo(info);
+
+out:
+ return NULL;
+}
+
+static struct packet *liveinfo_pkg_list(pid_t pid, int handle, const struct packet *packet)
+{
+ Eina_List *l;
+ Eina_List *list;
+ Eina_List *inst_list;
+ struct liveinfo *info;
+ struct pkg_info *pkg;
+ struct slave_node *slave;
+ FILE *fp;
+ const char *slavename;
+ double timestamp;
+
+ if (packet_get(packet, "d", &timestamp) != 1) {
+ ErrPrint("Invalid argument\n");
+ goto out;
+ }
+
+ info = liveinfo_find_by_pid(pid);
+ if (!info) {
+ ErrPrint("Invalid request\n");
+ goto out;
+ }
+
+ liveinfo_open_fifo(info);
+ fp = liveinfo_fifo(info);
+ if (!fp) {
+ liveinfo_close_fifo(info);
+ goto out;
+ }
+
+ list = (Eina_List *)package_list();
+ EINA_LIST_FOREACH(list, l, pkg) {
+ slave = package_slave(pkg);
+
+ if (slave) {
+ slavename = slave_name(slave);
+ pid = slave_pid(slave);
+ } else {
+ pid = (pid_t)-1;
+ slavename = "";
+ }
+
+ inst_list = (Eina_List *)package_instance_list(pkg);
+ fprintf(fp, "%d %s %s %s %d %d %d\n",
+ pid,
+ strlen(slavename) ? slavename : "(none)",
+ package_name(pkg),
+ package_abi(pkg),
+ package_refcnt(pkg),
+ package_fault_count(pkg),
+ eina_list_count(inst_list)
+ );
+ }
+
+ fprintf(fp, "EOD\n");
+ liveinfo_close_fifo(info);
+out:
+ return NULL;
+}
+
+static struct packet *liveinfo_slave_ctrl(pid_t pid, int handle, const struct packet *packet)
+{
+ return NULL;
+}
+
+static struct packet *liveinfo_pkg_ctrl(pid_t pid, int handle, const struct packet *packet)
+{
+ struct liveinfo *info;
+ FILE *fp;
+ char *cmd;
+ char *pkgname;
+ char *id;
+
+ if (packet_get(packet, "sss", &cmd, &pkgname, &id) != 3) {
+ ErrPrint("Invalid argument\n");
+ goto out;
+ }
+
+ info = liveinfo_find_by_pid(pid);
+ if (!info) {
+ ErrPrint("Invalid request\n");
+ goto out;
+ }
+
+ liveinfo_open_fifo(info);
+ fp = liveinfo_fifo(info);
+ if (!fp) {
+ liveinfo_close_fifo(info);
+ goto out;
+ }
+
+ if (!strcmp(cmd, "rmpack")) {
+ fprintf(fp, "%d\n", ENOSYS);
+ } else if (!strcmp(cmd, "rminst")) {
+ struct inst_info *inst;
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ fprintf(fp, "%d\n", ENOENT);
+ } else {
+ instance_destroy(inst);
+ fprintf(fp, "%d\n", 0);
+ }
+ }
+
+ fprintf(fp, "EOD\n");
+ liveinfo_close_fifo(info);
+
+out:
+ return NULL;
+}
+
+static struct packet *liveinfo_master_ctrl(pid_t pid, int handle, const struct packet *packet)
+{
+ struct liveinfo *info;
+ char *cmd;
+ char *var;
+ char *val;
+ FILE *fp;
+ int ret = -EINVAL;
+
+ if (packet_get(packet, "sss", &cmd, &var, &val) != 3) {
+ ErrPrint("Invalid argument\n");
+ goto out;
+ }
+
+ info = liveinfo_find_by_pid(pid);
+ if (!info) {
+ ErrPrint("Invalid request\n");
+ goto out;
+ }
+
+ if (!strcasecmp(var, "debug")) {
+ if (!strcasecmp(cmd, "set")) {
+ g_conf.debug_mode = !strcasecmp(val, "on");
+ } else if (!strcasecmp(cmd, "get")) {
+ }
+ ret = g_conf.debug_mode;
+ } else if (!strcasecmp(var, "slave_max_load")) {
+ if (!strcasecmp(cmd, "set")) {
+ g_conf.slave_max_load = atoi(val);
+ } else if (!strcasecmp(cmd, "get")) {
+ }
+ ret = g_conf.slave_max_load;
+ }
+
+ liveinfo_open_fifo(info);
+ fp = liveinfo_fifo(info);
+ if (!fp) {
+ liveinfo_close_fifo(info);
+ goto out;
+ }
+ fprintf(fp, "%d\nEOD\n", ret);
+ liveinfo_close_fifo(info);
+
+out:
+ return NULL;
+}
+
+static struct method s_info_table[] = {
+ {
+ .cmd = "liveinfo_hello",
+ .handler = liveinfo_hello,
+ },
+ {
+ .cmd = "slave_list",
+ .handler = liveinfo_slave_list,
+ },
+ {
+ .cmd = "pkg_list",
+ .handler = liveinfo_pkg_list,
+ },
+ {
+ .cmd = "inst_list",
+ .handler = liveinfo_inst_list,
+ },
+ {
+ .cmd = "slave_ctrl",
+ .handler = liveinfo_slave_ctrl,
+ },
+ {
+ .cmd = "pkg_ctrl",
+ .handler = liveinfo_pkg_ctrl,
+ },
+ {
+ .cmd = "master_ctrl",
+ .handler = liveinfo_master_ctrl,
+ },
+ {
+ .cmd = NULL,
+ .handler = NULL,
+ },
+};
+
+static struct method s_client_table[] = {
+ {
+ .cmd = "pd_mouse_move",
+ .handler = client_pd_mouse_move, /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+ },
+ {
+ .cmd = "lb_mouse_move",
+ .handler = client_lb_mouse_move, /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+ },
+ {
+ .cmd = "pd_mouse_down",
+ .handler = client_pd_mouse_down, /* pid, pkgname, id, width, height, timestamp, x, y, ret */
+ },
+ {
+ .cmd = "pd_mouse_up",
+ .handler = client_pd_mouse_up, /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+ },
+ {
+ .cmd = "lb_mouse_down",
+ .handler = client_lb_mouse_down, /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+ },
+ {
+ .cmd = "lb_mouse_up",
+ .handler = client_lb_mouse_up, /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+ },
+ {
+ .cmd = "pd_mouse_enter",
+ .handler = client_pd_mouse_enter, /* pid, pkgname, id, width, height, timestamp, x, y, ret */
+ },
+ {
+ .cmd = "pd_mouse_leave",
+ .handler = client_pd_mouse_leave, /* pid, pkgname, id, width, height, timestamp, x, y, ret */
+ },
+ {
+ .cmd = "lb_mouse_enter",
+ .handler = client_lb_mouse_enter, /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+ },
+ {
+ .cmd = "lb_mouse_leave",
+ .handler = client_lb_mouse_leave, /* pid, pkgname, filename, width, height, timestamp, x, y, ret */
+ },
+ {
+ .cmd = "change,visibility",
+ .handler = client_change_visibility,
+ },
+ {
+ .cmd = "lb_acquire_pixmap",
+ .handler = client_lb_acquire_pixmap,
+ },
+ {
+ .cmd = "lb_release_pixmap",
+ .handler = client_lb_release_pixmap,
+ },
+ {
+ .cmd = "pd_acquire_pixmap",
+ .handler = client_pd_acquire_pixmap,
+ },
+ {
+ .cmd = "pd_release_pixmap",
+ .handler = client_pd_release_pixmap,
+ },
+ {
+ .cmd = "acquire",
+ .handler = client_acquire, /*!< pid, ret */
+ },
+ {
+ .cmd = "release",
+ .handler = cilent_release, /*!< pid, ret */
+ },
+ {
+ .cmd = "clicked",
+ .handler = client_clicked, /*!< pid, pkgname, filename, event, timestamp, x, y, ret */
+ },
+ {
+ .cmd = "text_signal",
+ .handler = client_text_signal, /* pid, pkgname, filename, emission, source, s, sy, ex, ey, ret */
+ },
+ {
+ .cmd = "delete",
+ .handler = client_delete, /* pid, pkgname, filename, ret */
+ },
+ {
+ .cmd = "resize",
+ .handler = client_resize, /* pid, pkgname, filename, w, h, ret */
+ },
+ {
+ .cmd = "new",
+ .handler = client_new, /* pid, timestamp, pkgname, content, cluster, category, period, ret */
+ },
+ {
+ .cmd = "set_period",
+ .handler = client_set_period, /* pid, pkgname, filename, period, ret, period */
+ },
+ {
+ .cmd = "change_group",
+ .handler = client_change_group, /* pid, pkgname, filename, cluster, category, ret */
+ },
+ {
+ .cmd = "pinup_changed",
+ .handler = client_pinup_changed, /* pid, pkgname, filename, pinup, ret */
+ },
+ {
+ .cmd = "create_pd",
+ .handler = client_create_pd, /* pid, pkgname, filename, ret */
+ },
+ {
+ .cmd = "pd_move",
+ .handler = client_pd_move, /* pkgname, id, x, y */
+ },
+ {
+ .cmd = "destroy_pd",
+ .handler = client_destroy_pd, /* pid, pkgname, filename, ret */
+ },
+ {
+ .cmd = "activate_package",
+ .handler = client_activate_package, /* pid, pkgname, ret */
+ },
+ {
+ .cmd = "subscribe", /* pid, cluster, sub-cluster */
+ .handler = client_subscribed,
+ },
+ {
+ .cmd = "unsubscribe", /* pid, cluster, sub-cluster */
+ .handler = client_unsubscribed,
+ },
+ {
+ .cmd = "delete_cluster",
+ .handler = client_delete_cluster,
+ },
+ {
+ .cmd = "delete_category",
+ .handler = client_delete_category,
+ },
+ {
+ .cmd = "refresh_group",
+ .handler = client_refresh_group,
+ },
+ {
+ .cmd = "update",
+ .handler = client_update,
+ },
+
+ {
+ .cmd = "pd_access_read",
+ .handler = client_pd_access_read,
+ },
+ {
+ .cmd = "pd_access_read_prev",
+ .handler = client_pd_access_read_prev,
+ },
+ {
+ .cmd = "pd_access_read_next",
+ .handler = client_pd_access_read_next,
+ },
+ {
+ .cmd = "pd_access_activate",
+ .handler = client_pd_access_activate,
+ },
+
+ {
+ .cmd = "lb_access_read",
+ .handler = client_lb_access_read,
+ },
+ {
+ .cmd = "lb_access_read_prev",
+ .handler = client_lb_access_read_prev,
+ },
+ {
+ .cmd = "lb_access_read_next",
+ .handler = client_lb_access_read_next,
+ },
+ {
+ .cmd = "lb_access_activate",
+ .handler = client_lb_access_activate,
+ },
+
+ {
+ .cmd = "lb_key_down",
+ .handler = client_lb_key_down,
+ },
+ {
+ .cmd = "lb_key_up",
+ .handler = client_lb_key_up,
+ },
+
+ {
+ .cmd = "pd_key_down",
+ .handler = client_pd_key_down,
+ },
+ {
+ .cmd = "pd_key_up",
+ .handler = client_pd_key_up,
+ },
+
+ {
+ .cmd = "client_paused",
+ .handler = client_pause_request,
+ },
+ {
+ .cmd = "client_resumed",
+ .handler = client_resume_request,
+ },
+
+ {
+ .cmd = NULL,
+ .handler = NULL,
+ },
+};
+
+static struct method s_service_table[] = {
+ {
+ .cmd = "service_update",
+ .handler = service_update,
+ },
+ {
+ .cmd = "service_change_period",
+ .handler = service_change_period,
+ },
+ {
+ .cmd = NULL,
+ .handler = NULL,
+ },
+};
+
+static struct method s_slave_table[] = {
+ {
+ .cmd = "hello",
+ .handler = slave_hello, /* slave_name, ret */
+ },
+ {
+ .cmd = "ping",
+ .handler = slave_ping, /* slave_name, ret */
+ },
+ {
+ .cmd = "call",
+ .handler = slave_call, /* slave_name, pkgname, filename, function, ret */
+ },
+ {
+ .cmd = "ret",
+ .handler = slave_ret, /* slave_name, pkgname, filename, function, ret */
+ },
+ {
+ .cmd = "updated",
+ .handler = slave_updated, /* slave_name, pkgname, filename, width, height, priority, ret */
+ },
+ {
+ .cmd = "desc_updated",
+ .handler = slave_desc_updated, /* slave_name, pkgname, filename, decsfile, ret */
+ },
+ {
+ .cmd = "deleted",
+ .handler = slave_deleted, /* slave_name, pkgname, filename, ret */
+ },
+ {
+ .cmd = "acquire_buffer",
+ .handler = slave_acquire_buffer, /* slave_name, id, w, h, size, - out - type, shmid */
+ },
+ {
+ .cmd = "resize_buffer",
+ .handler = slave_resize_buffer,
+ },
+ {
+ .cmd = "release_buffer",
+ .handler = slave_release_buffer, /* slave_name, id - ret */
+ },
+ {
+ .cmd = "faulted",
+ .handler = slave_faulted, /* slave_name, pkgname, id, funcname */
+ },
+ {
+ .cmd = NULL,
+ .handler = NULL,
+ },
+};
+
+HAPI int server_init(void)
+{
+ com_core_packet_use_thread(COM_CORE_THREAD);
+
+ if (unlink(INFO_SOCKET) < 0)
+ ErrPrint("info socket: %s\n", strerror(errno));
+
+ if (unlink(SLAVE_SOCKET) < 0)
+ ErrPrint("slave socket: %s\n", strerror(errno));
+
+ if (unlink(CLIENT_SOCKET) < 0)
+ ErrPrint("client socket: %s\n", strerror(errno));
+
+ if (unlink(SERVICE_SOCKET) < 0)
+ ErrPrint("service socket: %s\n", strerror(errno));
+
+ s_info.info_fd = com_core_packet_server_init(INFO_SOCKET, s_info_table);
+ if (s_info.info_fd < 0)
+ ErrPrint("Failed to create a info socket\n");
+
+ s_info.slave_fd = com_core_packet_server_init(SLAVE_SOCKET, s_slave_table);
+ if (s_info.slave_fd < 0)
+ ErrPrint("Failed to create a slave socket\n");
+
+ s_info.client_fd = com_core_packet_server_init(CLIENT_SOCKET, s_client_table);
+ if (s_info.client_fd < 0)
+ ErrPrint("Failed to create a client socket\n");
+
+ s_info.service_fd = com_core_packet_server_init(SERVICE_SOCKET, s_service_table);
+ if (s_info.service_fd < 0)
+ ErrPrint("Faild to create a service socket\n");
+
+ if (chmod(INFO_SOCKET, 0600) < 0)
+ ErrPrint("info socket: %s\n", strerror(errno));
+
+ if (chmod(SLAVE_SOCKET, 0666) < 0)
+ ErrPrint("slave socket: %s\n", strerror(errno));
+
+ if (chmod(CLIENT_SOCKET, 0666) < 0)
+ ErrPrint("client socket: %s\n", strerror(errno));
+
+ if (chmod(SERVICE_SOCKET, 0666) < 0)
+ ErrPrint("service socket: %s\n", strerror(errno));
+
+ return 0;
+}
+
+HAPI int server_fini(void)
+{
+ if (s_info.info_fd > 0) {
+ com_core_packet_server_fini(s_info.info_fd);
+ s_info.info_fd = -1;
+ }
+
+ if (s_info.slave_fd > 0) {
+ com_core_packet_server_fini(s_info.slave_fd);
+ s_info.slave_fd = -1;
+ }
+
+ if (s_info.client_fd > 0) {
+ com_core_packet_server_fini(s_info.client_fd);
+ s_info.client_fd = -1;
+ }
+
+ if (s_info.service_fd > 0) {
+ com_core_packet_server_fini(s_info.service_fd);
+ s_info.service_fd = -1;
+ }
+
+ return 0;
+}
+
+/* End of a file */
diff --git a/src/setting.c b/src/setting.c
new file mode 100644
index 0000000..7ac5700
--- /dev/null
+++ b/src/setting.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <vconf.h>
+#include <dlog.h>
+
+#include <Eina.h>
+
+#include "client_life.h"
+#include "setting.h"
+#include "util.h"
+#include "debug.h"
+#include "slave_life.h"
+#include "critical_log.h"
+#include "xmonitor.h"
+#include "conf.h"
+
+int errno;
+
+static void lcd_state_cb(keynode_t *node, void *user_data)
+{
+ if (!node)
+ return;
+
+ xmonitor_handle_state_changes();
+}
+
+HAPI int setting_is_lcd_off(void)
+{
+ int state;
+
+ if (vconf_get_int(VCONFKEY_PM_STATE, &state) != 0) {
+ ErrPrint("Idle lock state is not valid\n");
+ state = VCONFKEY_PM_STATE_NORMAL; /* UNLOCK */
+ }
+
+ DbgPrint("State: %d, (%d:lcdoff, %d:sleep)\n", state, VCONFKEY_PM_STATE_LCDOFF, VCONFKEY_PM_STATE_SLEEP);
+ return state == VCONFKEY_PM_STATE_LCDOFF || state == VCONFKEY_PM_STATE_SLEEP;
+}
+
+static void power_off_cb(keynode_t *node, void *user_data)
+{
+ int val;
+ CRITICAL_LOG("Terminated(vconf)\n");
+
+ if (vconf_get_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, &val) != 0) {
+ ErrPrint("Failed to get power off status (%d)\n", val);
+ return;
+ }
+
+ if (val == VCONFKEY_SYSMAN_POWER_OFF_DIRECT || val == VCONFKEY_SYSMAN_POWER_OFF_RESTART) {
+ if (creat("/tmp/.stop.provider", 0644) < 0)
+ ErrPrint("Failed to create .stop.provider [%s]\n", strerror(errno));
+
+ exit(0);
+ } else {
+ ErrPrint("Unknown power state: %d\n", val);
+ }
+}
+
+HAPI int setting_init(void)
+{
+ int ret;
+
+ ret = vconf_notify_key_changed(VCONFKEY_PM_STATE, lcd_state_cb, NULL);
+ if (ret < 0)
+ ErrPrint("Failed to add vconf for lock state\n");
+
+ ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, power_off_cb, NULL);
+ if (ret < 0)
+ ErrPrint("Failed to add vconf for power state\n");
+
+ return ret;
+}
+
+HAPI int setting_fini(void)
+{
+ int ret;
+ ret = vconf_ignore_key_changed(VCONFKEY_PM_STATE, lcd_state_cb);
+ ret = vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, power_off_cb);
+ return ret;
+}
+
+/* End of a file */
diff --git a/src/slave_life.c b/src/slave_life.c
new file mode 100644
index 0000000..3665b4d
--- /dev/null
+++ b/src/slave_life.c
@@ -0,0 +1,1291 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h> /* strerror */
+#include <errno.h> /* errno */
+#include <unistd.h> /* pid_t */
+#include <stdlib.h> /* free */
+#include <pthread.h>
+#include <malloc.h>
+#include <sys/time.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+
+#include <aul.h> /* aul_launch_app */
+#include <dlog.h>
+#include <bundle.h>
+
+#include <packet.h>
+
+#include "slave_life.h"
+#include "slave_rpc.h"
+#include "client_life.h"
+#include "fault_manager.h"
+#include "debug.h"
+#include "conf.h"
+#include "setting.h"
+#include "util.h"
+#include "abi.h"
+#include "xmonitor.h"
+
+int errno;
+
+struct slave_node {
+ char *name;
+ char *abi;
+ char *pkgname;
+ int secured; /* Only A package(livebox) is loaded for security requirements */
+ int refcnt;
+ int fault_count;
+ int critical_fault_count;
+ enum slave_state state;
+
+ int loaded_instance;
+ int loaded_package;
+
+ int reactivate_instances;
+ int reactivate_slave;
+
+ pid_t pid;
+
+ Eina_List *event_activate_list;
+ Eina_List *event_deactivate_list;
+ Eina_List *event_delete_list;
+ Eina_List *event_fault_list;
+ Eina_List *event_pause_list;
+ Eina_List *event_resume_list;
+
+ Eina_List *data_list;
+
+ Ecore_Timer *ttl_timer; /* Time to live */
+ Ecore_Timer *activate_timer; /* Waiting hello packet for this time */
+
+ struct timeval activated_at;
+};
+
+struct event {
+ struct slave_node *slave;
+
+ int (*evt_cb)(struct slave_node *, void *);
+ void *cbdata;
+};
+
+struct priv_data {
+ char *tag;
+ void *data;
+};
+
+static struct {
+ Eina_List *slave_list;
+} s_info = {
+ .slave_list = NULL,
+};
+
+static Eina_Bool slave_ttl_cb(void *data)
+{
+ struct slave_node *slave = (struct slave_node *)data;
+
+ /*!
+ * \note
+ * ttl_timer must has to be set to NULL before deactivate the slave
+ * It will be used for making decision of the expired TTL timer or the fault of a livebox.
+ */
+ slave->ttl_timer = NULL;
+
+ slave_set_reactivation(slave, 0);
+ slave_set_reactivate_instances(slave, 1);
+
+ slave = slave_deactivate(slave);
+ DbgPrint("Slave is deactivated(%p)\n", slave);
+
+ /*! To recover all instances state it is activated again */
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static inline int xmonitor_pause_cb(void *data)
+{
+ slave_pause(data);
+ return 0;
+}
+
+static inline int xmonitor_resume_cb(void *data)
+{
+ slave_resume(data);
+ return 0;
+}
+
+static inline struct slave_node *create_slave_node(const char *name, int is_secured, const char *abi, const char *pkgname)
+{
+ struct slave_node *slave;
+
+ slave = calloc(1, sizeof(*slave));
+ if (!slave) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ slave->name = strdup(name);
+ if (!slave->name) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(slave);
+ return NULL;
+ }
+
+ slave->abi = strdup(abi);
+ if (!slave->abi) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(slave->name);
+ DbgFree(slave);
+ return NULL;
+ }
+
+ slave->pkgname = strdup(pkgname);
+ if (!slave->pkgname) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(slave->abi);
+ DbgFree(slave->name);
+ DbgFree(slave);
+ return NULL;
+ }
+
+ slave->secured = is_secured;
+ slave->pid = (pid_t)-1;
+ slave->state = SLAVE_TERMINATED;
+
+ xmonitor_add_event_callback(XMONITOR_PAUSED, xmonitor_pause_cb, slave);
+ xmonitor_add_event_callback(XMONITOR_RESUMED, xmonitor_resume_cb, slave);
+
+ s_info.slave_list = eina_list_append(s_info.slave_list, slave);
+ DbgPrint("slave data is created %p\n", slave);
+ return slave;
+}
+
+static inline void invoke_delete_cb(struct slave_node *slave)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct event *event;
+ int ret;
+
+ EINA_LIST_FOREACH_SAFE(slave->event_delete_list, l, n, event) {
+ ret = event->evt_cb(event->slave, event->cbdata);
+ if (ret < 0) {
+ if (eina_list_data_find(slave->event_delete_list, event)) {
+ slave->event_delete_list = eina_list_remove(slave->event_delete_list, event);
+ DbgFree(event);
+ }
+ }
+ }
+}
+
+static inline void destroy_slave_node(struct slave_node *slave)
+{
+ struct event *event;
+ struct priv_data *priv;
+
+ if (slave->pid != (pid_t)-1) {
+ ErrPrint("Slave is not deactivated\n");
+ return;
+ }
+
+ DbgPrint("Slave data is destroyed %p\n", slave);
+
+ xmonitor_del_event_callback(XMONITOR_PAUSED, xmonitor_pause_cb, slave);
+ xmonitor_del_event_callback(XMONITOR_RESUMED, xmonitor_resume_cb, slave);
+
+ invoke_delete_cb(slave);
+ slave_rpc_fini(slave); /*!< Finalize the RPC after handling all delete callbacks */
+
+ EINA_LIST_FREE(slave->event_delete_list, event) {
+ DbgFree(event);
+ }
+
+ EINA_LIST_FREE(slave->event_activate_list, event) {
+ DbgFree(event);
+ }
+
+ EINA_LIST_FREE(slave->event_deactivate_list, event) {
+ DbgFree(event);
+ }
+
+ EINA_LIST_FREE(slave->event_fault_list, event) {
+ DbgFree(event);
+ }
+
+ EINA_LIST_FREE(slave->data_list, priv) {
+ DbgFree(priv->tag);
+ DbgFree(priv);
+ }
+
+ s_info.slave_list = eina_list_remove(s_info.slave_list, slave);
+
+ if (slave->ttl_timer)
+ ecore_timer_del(slave->ttl_timer);
+
+ if (slave->activate_timer)
+ ecore_timer_del(slave->activate_timer);
+
+ DbgFree(slave->abi);
+ DbgFree(slave->name);
+ DbgFree(slave->pkgname);
+ DbgFree(slave);
+ return;
+}
+
+static inline struct slave_node *find_slave(const char *name)
+{
+ struct slave_node *slave;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(s_info.slave_list, l, slave) {
+ if (!strcmp(slave->name, name))
+ return slave;
+ }
+
+ return NULL;
+}
+
+HAPI int slave_expired_ttl(struct slave_node *slave)
+{
+ if (!slave)
+ return 0;
+
+ if (!slave->secured)
+ return 0;
+
+ return !!slave->ttl_timer;
+}
+
+HAPI struct slave_node *slave_ref(struct slave_node *slave)
+{
+ if (!slave)
+ return NULL;
+
+ slave->refcnt++;
+ return slave;
+}
+
+HAPI struct slave_node *slave_unref(struct slave_node *slave)
+{
+ if (!slave)
+ return NULL;
+
+ if (slave->refcnt == 0) {
+ ErrPrint("Slave refcnt is not valid\n");
+ return NULL;
+ }
+
+ slave->refcnt--;
+ if (slave->refcnt == 0) {
+ destroy_slave_node(slave);
+ slave = NULL;
+ }
+
+ return slave;
+}
+
+HAPI const int const slave_refcnt(struct slave_node *slave)
+{
+ return slave->refcnt;
+}
+
+HAPI struct slave_node *slave_create(const char *name, int is_secured, const char *abi, const char *pkgname)
+{
+ struct slave_node *slave;
+
+ slave = find_slave(name);
+ if (slave) {
+ if (slave->secured != is_secured)
+ ErrPrint("Exists slave and creating slave's security flag is not matched\n");
+ return slave;
+ }
+
+ slave = create_slave_node(name, is_secured, abi, pkgname);
+ if (!slave)
+ return NULL;
+
+ slave_ref(slave);
+ slave_rpc_init(slave);
+
+ return slave;
+}
+
+/*!
+ * \note
+ * Before destroying slave object,
+ * you should check the RPC(slave_async_XXX) state and Private data field (slave_set_data)
+ */
+HAPI void slave_destroy(struct slave_node *slave)
+{
+ slave_unref(slave);
+}
+
+static inline void invoke_fault_cb(struct slave_node *slave)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct event *event;
+ int ret;
+
+ EINA_LIST_FOREACH_SAFE(slave->event_fault_list, l, n, event) {
+ ret = event->evt_cb(event->slave, event->cbdata);
+ if (ret < 0) {
+ if (eina_list_data_find(slave->event_fault_list, event)) {
+ slave->event_fault_list = eina_list_remove(slave->event_fault_list, event);
+ DbgFree(event);
+ }
+ }
+ }
+}
+
+static inline void invoke_activate_cb(struct slave_node *slave)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct event *event;
+ int ret;
+
+ EINA_LIST_FOREACH_SAFE(slave->event_activate_list, l, n, event) {
+ ret = event->evt_cb(event->slave, event->cbdata);
+ if (ret < 0) {
+ if (eina_list_data_find(slave->event_activate_list, event)) {
+ slave->event_activate_list = eina_list_remove(slave->event_activate_list, event);
+ DbgFree(event);
+ }
+ }
+ }
+}
+
+static Eina_Bool activate_timer_cb(void *data)
+{
+ struct slave_node *slave = data;
+
+ slave->fault_count++;
+ invoke_fault_cb(slave);
+
+ slave_set_reactivation(slave, 0);
+ slave_set_reactivate_instances(slave, 0);
+
+ slave->activate_timer = NULL;
+ if (slave->pid > 0) {
+ int ret;
+ DbgPrint("Try to terminate PID: %d\n", slave->pid);
+ ret = aul_terminate_pid(slave->pid);
+ if (ret < 0)
+ ErrPrint("Terminate failed, pid %d\n", slave->pid);
+ }
+ slave = slave_deactivated(slave);
+ ErrPrint("Slave is not activated in %lf sec (slave: %p)\n", SLAVE_ACTIVATE_TIME, slave);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+HAPI int slave_activate(struct slave_node *slave)
+{
+
+ /*!
+ * \note
+ * This check code can replace the slave->state check code
+ * If the slave data has the PID, it means, it is activated
+ * Even if it is in the termiating sequence, it will have the PID
+ * before terminated at last.
+ * So we can use this simple code for checking the slave's last state.
+ * about it is alive? or not.
+ */
+ if (slave->pid != (pid_t)-1)
+ return -EALREADY;
+
+ if (DEBUG_MODE) {
+ DbgPrint("Debug Mode enabled. name[%s] secured[%d] abi[%s]\n", slave->name, slave->secured, slave->abi);
+ } else {
+ bundle *param;
+ param = bundle_create();
+ if (!param) {
+ ErrPrint("Failed to create a bundle\n");
+ return -EFAULT;
+ }
+
+ bundle_add(param, BUNDLE_SLAVE_NAME, slave->name);
+ bundle_add(param, BUNDLE_SLAVE_SECURED, slave->secured ? "true" : "false");
+ bundle_add(param, BUNDLE_SLAVE_ABI, slave->abi);
+
+ DbgPrint("Launch the slave package: %s\n", slave->pkgname);
+ slave->pid = (pid_t)aul_launch_app(slave->pkgname, param);
+
+ bundle_free(param);
+
+ if (slave->pid < 0) {
+ ErrPrint("Failed to launch a new slave %s (%d)\n", slave->name, slave->pid);
+ slave->pid = (pid_t)-1;
+ return -EFAULT;
+ }
+ DbgPrint("Slave launched %d for %s\n", slave->pid, slave->name);
+
+ slave->activate_timer = ecore_timer_add(SLAVE_ACTIVATE_TIME, activate_timer_cb, slave);
+ if (!slave->activate_timer)
+ ErrPrint("Failed to register an activate timer\n");
+ }
+
+ slave->state = SLAVE_REQUEST_TO_LAUNCH;
+ /*!
+ * \note
+ * Increase the refcnt of a slave,
+ * To prevent from making an orphan(slave).
+ */
+ slave_ref(slave);
+
+ return 0;
+}
+
+HAPI int slave_give_more_ttl(struct slave_node *slave)
+{
+ double delay;
+
+ if (!slave->secured || !slave->ttl_timer)
+ return -EINVAL;
+
+ delay = SLAVE_TTL - ecore_timer_pending_get(slave->ttl_timer);
+ ecore_timer_delay(slave->ttl_timer, delay);
+ return 0;
+}
+
+HAPI int slave_freeze_ttl(struct slave_node *slave)
+{
+ if (!slave->secured || !slave->ttl_timer)
+ return -EINVAL;
+
+ ecore_timer_freeze(slave->ttl_timer);
+ return 0;
+}
+
+HAPI int slave_thaw_ttl(struct slave_node *slave)
+{
+ double delay;
+
+ if (!slave->secured || !slave->ttl_timer)
+ return -EINVAL;
+
+ ecore_timer_thaw(slave->ttl_timer);
+
+ delay = SLAVE_TTL - ecore_timer_pending_get(slave->ttl_timer);
+ ecore_timer_delay(slave->ttl_timer, delay);
+ return 0;
+}
+
+HAPI int slave_activated(struct slave_node *slave)
+{
+ slave->state = SLAVE_RESUMED;
+
+ if (xmonitor_is_paused())
+ slave_pause(slave);
+
+ if (slave->secured == 1) {
+ DbgPrint("Slave deactivation timer is added (%s - %lf)\n", slave->name, SLAVE_TTL);
+ slave->ttl_timer = ecore_timer_add(SLAVE_TTL, slave_ttl_cb, slave);
+ if (!slave->ttl_timer)
+ ErrPrint("Failed to create a TTL timer\n");
+ }
+
+ invoke_activate_cb(slave);
+
+ slave_set_reactivation(slave, 0);
+ slave_set_reactivate_instances(slave, 0);
+
+ if (gettimeofday(&slave->activated_at, NULL) < 0)
+ ErrPrint("Failed to get time of day: %s\n", strerror(errno));
+
+ if (slave->activate_timer) {
+ ecore_timer_del(slave->activate_timer);
+ slave->activate_timer = NULL;
+ }
+
+ return 0;
+}
+
+static inline int invoke_deactivate_cb(struct slave_node *slave)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct event *event;
+ int ret;
+ int reactivate = 0;
+
+ EINA_LIST_FOREACH_SAFE(slave->event_deactivate_list, l, n, event) {
+ ret = event->evt_cb(event->slave, event->cbdata);
+ if (ret < 0) {
+ if (eina_list_data_find(slave->event_deactivate_list, event)) {
+ slave->event_deactivate_list = eina_list_remove(slave->event_deactivate_list, event);
+ DbgFree(event);
+ }
+ } else if (ret == SLAVE_NEED_TO_REACTIVATE) {
+ reactivate++;
+ }
+ }
+
+ return reactivate;
+}
+
+HAPI struct slave_node *slave_deactivate(struct slave_node *slave)
+{
+ int ret;
+
+ if (!slave_is_activated(slave)) {
+ ErrPrint("Slave is already deactivated\n");
+ if (slave_loaded_instance(slave) == 0) {
+ /*!
+ * \note
+ * If a slave has no more instances,
+ * Destroy it
+ */
+ slave = slave_unref(slave);
+ }
+ return slave;
+ }
+
+ DbgPrint("Deactivate a slave: %d\n", slave->pid);
+ /*!
+ * \todo
+ * check the return value of the aul_terminate_pid
+ */
+ slave->state = SLAVE_REQUEST_TO_TERMINATE;
+
+ DbgPrint("Terminate PID: %d\n", slave->pid);
+ if (slave->pid > 0) {
+ ret = aul_terminate_pid(slave->pid);
+ if (ret < 0) {
+ ErrPrint("Terminate failed. pid %d (%d)\n", slave->pid, ret);
+ slave = slave_deactivated(slave);
+ }
+ }
+
+ return slave;
+}
+
+HAPI struct slave_node *slave_deactivated(struct slave_node *slave)
+{
+ int reactivate;
+
+ slave->pid = (pid_t)-1;
+ slave->state = SLAVE_TERMINATED;
+
+ if (slave->ttl_timer) {
+ ecore_timer_del(slave->ttl_timer);
+ slave->ttl_timer = NULL;
+ }
+
+ if (slave->activate_timer) {
+ ecore_timer_del(slave->activate_timer);
+ slave->activate_timer = NULL;
+ }
+
+ reactivate = invoke_deactivate_cb(slave);
+
+ slave = slave_unref(slave);
+ if (!slave) {
+ DbgPrint("SLAVE object is destroyed\n");
+ return slave;
+ }
+
+ if (reactivate && slave_need_to_reactivate(slave)) {
+ int ret;
+
+ DbgPrint("Need to reactivate a slave\n");
+ ret = slave_activate(slave);
+ if (ret < 0 && ret != -EALREADY)
+ ErrPrint("Failed to reactivate a slave\n");
+ } else if (slave_loaded_instance(slave) == 0) {
+ /*!
+ * \note
+ * If a slave has no more instances,
+ * Destroy it
+ */
+ slave = slave_unref(slave);
+ }
+
+ return slave;
+}
+
+HAPI struct slave_node *slave_deactivated_by_fault(struct slave_node *slave)
+{
+ int ret;
+ struct timeval faulted_at;
+ int reactivate = 1;
+ int reactivate_instances = 1;
+
+ if (!slave_is_activated(slave)) {
+ DbgPrint("Deactivating in progress\n");
+ if (slave_loaded_instance(slave) == 0)
+ slave = slave_unref(slave);
+
+ return slave;
+ }
+
+ slave->fault_count++;
+
+ (void)fault_check_pkgs(slave);
+
+ if (slave->pid > 0) {
+ DbgPrint("Try to terminate PID: %d\n", slave->pid);
+ ret = aul_terminate_pid(slave->pid);
+ if (ret < 0) {
+ ErrPrint("Terminate failed, pid %d\n", slave->pid);
+ }
+ }
+
+ if (gettimeofday(&faulted_at, NULL) == 0) {
+ struct timeval rtv;
+
+ timersub(&faulted_at, &slave->activated_at, &rtv);
+ if (rtv.tv_sec < MINIMUM_REACTIVATION_TIME) {
+ slave->critical_fault_count++;
+ if (!slave_loaded_instance(slave) || slave->critical_fault_count >= SLAVE_MAX_LOAD) {
+ ErrPrint("Reactivation time is too fast and frequently occurred - Stop to auto reactivation\n");
+ reactivate = 0;
+ reactivate_instances = 0;
+ slave->critical_fault_count = 0;
+ /*!
+ * \note
+ * Fault callback can access the slave information.
+ */
+ invoke_fault_cb(slave);
+ }
+ } else {
+ slave->critical_fault_count = 0;
+ }
+ } else {
+ ErrPrint("Failed to get time of day: %s\n", strerror(errno));
+ }
+
+ slave_set_reactivation(slave, reactivate);
+ slave_set_reactivate_instances(slave, reactivate_instances);
+
+ slave = slave_deactivated(slave);
+ return slave;
+}
+
+HAPI const int const slave_is_activated(struct slave_node *slave)
+{
+ switch (slave->state) {
+ case SLAVE_REQUEST_TO_TERMINATE:
+ case SLAVE_TERMINATED:
+ return 0;
+ case SLAVE_REQUEST_TO_LAUNCH:
+ /* Not yet launched. but the slave incurred an unexpected error */
+ case SLAVE_REQUEST_TO_PAUSE:
+ case SLAVE_REQUEST_TO_RESUME:
+ case SLAVE_PAUSED:
+ case SLAVE_RESUMED:
+ return 1;
+ default:
+ return slave->pid != (pid_t)-1;
+ }
+
+ /* Could not be reach to here */
+ return 0;
+}
+
+HAPI int slave_event_callback_add(struct slave_node *slave, enum slave_event event, int (*cb)(struct slave_node *, void *), void *data)
+{
+ struct event *ev;
+
+ ev = calloc(1, sizeof(*ev));
+ if (!ev) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ ev->slave = slave;
+ ev->cbdata = data;
+ ev->evt_cb = cb;
+
+ /*!
+ * \note
+ * Use the eina_list_prepend API.
+ * To keep the sequence of a callback invocation.
+ *
+ * Here is an example sequence.
+ *
+ * slave_event_callback_add(CALLBACK_01);
+ * slave_event_callback_add(CALLBACK_02);
+ * slave_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 SLAVE_EVENT_ACTIVATE:
+ slave->event_activate_list = eina_list_prepend(slave->event_activate_list, ev);
+ break;
+ case SLAVE_EVENT_DELETE:
+ slave->event_delete_list = eina_list_prepend(slave->event_delete_list, ev);
+ break;
+ case SLAVE_EVENT_DEACTIVATE:
+ slave->event_deactivate_list = eina_list_prepend(slave->event_deactivate_list, ev);
+ break;
+ case SLAVE_EVENT_PAUSE:
+ slave->event_pause_list = eina_list_prepend(slave->event_pause_list, ev);
+ break;
+ case SLAVE_EVENT_RESUME:
+ slave->event_resume_list = eina_list_prepend(slave->event_resume_list, ev);
+ break;
+ case SLAVE_EVENT_FAULT:
+ slave->event_fault_list = eina_list_prepend(slave->event_fault_list, ev);
+ break;
+ default:
+ DbgFree(ev);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+HAPI int slave_event_callback_del(struct slave_node *slave, enum slave_event event, int (*cb)(struct slave_node *, void *), void *data)
+{
+ struct event *ev;
+ Eina_List *l;
+ Eina_List *n;
+
+ switch (event) {
+ case SLAVE_EVENT_DEACTIVATE:
+ EINA_LIST_FOREACH_SAFE(slave->event_deactivate_list, l, n, ev) {
+ if (ev->evt_cb == cb && ev->cbdata == data) {
+ slave->event_deactivate_list = eina_list_remove(slave->event_deactivate_list, ev);
+ DbgFree(ev);
+ return 0;
+ }
+ }
+ break;
+ case SLAVE_EVENT_DELETE:
+ EINA_LIST_FOREACH_SAFE(slave->event_delete_list, l, n, ev) {
+ if (ev->evt_cb == cb && ev->cbdata == data) {
+ slave->event_delete_list = eina_list_remove(slave->event_delete_list, ev);
+ DbgFree(ev);
+ return 0;
+ }
+ }
+ break;
+ case SLAVE_EVENT_ACTIVATE:
+ EINA_LIST_FOREACH_SAFE(slave->event_activate_list, l, n, ev) {
+ if (ev->evt_cb == cb && ev->cbdata == data) {
+ slave->event_activate_list = eina_list_remove(slave->event_activate_list, ev);
+ DbgFree(ev);
+ return 0;
+ }
+ }
+ break;
+ case SLAVE_EVENT_PAUSE:
+ EINA_LIST_FOREACH_SAFE(slave->event_pause_list, l, n, ev) {
+ if (ev->evt_cb == cb && ev->cbdata == data) {
+ slave->event_pause_list = eina_list_remove(slave->event_pause_list, ev);
+ DbgFree(ev);
+ return 0;
+ }
+ }
+ break;
+ case SLAVE_EVENT_RESUME:
+ EINA_LIST_FOREACH_SAFE(slave->event_resume_list, l, n, ev) {
+ if (ev->evt_cb == cb && ev->cbdata == data) {
+ slave->event_resume_list = eina_list_remove(slave->event_resume_list, ev);
+ DbgFree(ev);
+ return 0;
+ }
+ }
+ break;
+ case SLAVE_EVENT_FAULT:
+ EINA_LIST_FOREACH_SAFE(slave->event_fault_list, l, n, ev) {
+ if (ev->evt_cb == cb && ev->cbdata == data) {
+ slave->event_fault_list = eina_list_remove(slave->event_fault_list, ev);
+ DbgFree(ev);
+ return 0;
+ }
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return -ENOENT;
+}
+
+HAPI int slave_set_data(struct slave_node *slave, const char *tag, void *data)
+{
+ struct priv_data *priv;
+
+ priv = calloc(1, sizeof(*priv));
+ if (!priv) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ priv->tag = strdup(tag);
+ if (!priv->tag) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(priv);
+ return -ENOMEM;
+ }
+
+ priv->data = data;
+ slave->data_list = eina_list_append(slave->data_list, priv);
+ return 0;
+}
+
+HAPI void *slave_del_data(struct slave_node *slave, const char *tag)
+{
+ struct priv_data *priv;
+ void *data;
+ Eina_List *l;
+ Eina_List *n;
+
+ EINA_LIST_FOREACH_SAFE(slave->data_list, l, n, priv) {
+ if (!strcmp(priv->tag, tag)) {
+ slave->data_list = eina_list_remove(slave->data_list, priv);
+
+ data = priv->data;
+ DbgFree(priv->tag);
+ DbgFree(priv);
+ return data;
+ }
+ }
+
+ return NULL;
+}
+
+HAPI void *slave_data(struct slave_node *slave, const char *tag)
+{
+ struct priv_data *priv;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(slave->data_list, l, priv) {
+ if (!strcmp(priv->tag, tag))
+ return priv->data;
+ }
+
+ return NULL;
+}
+
+HAPI struct slave_node *slave_find_by_pid(pid_t pid)
+{
+ Eina_List *l;
+ struct slave_node *slave;
+
+ EINA_LIST_FOREACH(s_info.slave_list, l, slave) {
+ if (slave->pid == pid)
+ return slave;
+ }
+
+ return NULL;
+}
+
+HAPI struct slave_node *slave_find_by_name(const char *name)
+{
+ Eina_List *l;
+ struct slave_node *slave;
+
+ EINA_LIST_FOREACH(s_info.slave_list, l, slave) {
+ if (!strcmp(slave->name, name))
+ return slave;
+ }
+
+ return NULL;
+}
+
+HAPI struct slave_node *slave_find_available(const char *abi, int secured)
+{
+ Eina_List *l;
+ struct slave_node *slave;
+
+ EINA_LIST_FOREACH(s_info.slave_list, l, slave) {
+ if (slave->secured != secured)
+ continue;
+
+ if (slave->state == SLAVE_REQUEST_TO_TERMINATE && slave->loaded_instance == 0) {
+ /*!
+ * \note
+ * If a slave is in request_to_terminate state,
+ * and the slave object has no more intances,
+ * the slave object will be deleted soon.
+ * so we cannot reuse it.
+ *
+ * This object is not usable.
+ */
+ continue;
+ }
+
+ if (strcasecmp(slave->abi, abi))
+ continue;
+
+ if (slave->secured) {
+ DbgPrint("Found secured slave - has no instances (%s)\n", slave_name(slave));
+ if (slave->loaded_package == 0)
+ return slave;
+ } else {
+ DbgPrint("slave[%s] %d\n", slave_name(slave), slave->loaded_package);
+ if (!strcasecmp(abi, DEFAULT_ABI)) {
+ if (slave->loaded_package < SLAVE_MAX_LOAD)
+ return slave;
+ } else {
+ return slave;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+HAPI struct slave_node *slave_find_by_pkgname(const char *pkgname)
+{
+ Eina_List *l;
+ struct slave_node *slave;
+
+ EINA_LIST_FOREACH(s_info.slave_list, l, slave) {
+ if (!strcmp(slave->pkgname, pkgname)) {
+ if (slave->pid == (pid_t)-1) {
+ return slave;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+HAPI struct slave_node *slave_find_by_rpc_handle(int handle)
+{
+ Eina_List *l;
+ struct slave_node *slave;
+
+ if (handle <= 0) {
+ ErrPrint("Invalid RPC handle: %d\n", handle);
+ return NULL;
+ }
+
+ EINA_LIST_FOREACH(s_info.slave_list, l, slave) {
+ if (slave_rpc_handle(slave) == handle)
+ return slave;
+ }
+
+ /* Not found */
+ return NULL;
+}
+
+HAPI void slave_load_package(struct slave_node *slave)
+{
+ slave->loaded_package++;
+}
+
+HAPI void slave_unload_package(struct slave_node *slave)
+{
+ if (!slave || slave->loaded_package == 0) {
+ ErrPrint("Slave loaded package is not correct\n");
+ return;
+ }
+
+ slave->loaded_package--;
+}
+
+HAPI void slave_load_instance(struct slave_node *slave)
+{
+ slave->loaded_instance++;
+ DbgPrint("Instance: (%d)%d\n", slave->pid, slave->loaded_instance);
+}
+
+HAPI int const slave_loaded_instance(struct slave_node *slave)
+{
+ return slave->loaded_instance;
+}
+
+HAPI int const slave_loaded_package(struct slave_node *slave)
+{
+ return slave->loaded_package;
+}
+
+HAPI struct slave_node *slave_unload_instance(struct slave_node *slave)
+{
+ if (!slave || slave->loaded_instance == 0) {
+ ErrPrint("Slave loaded instance is not correct\n");
+ return slave;
+ }
+
+ slave->loaded_instance--;
+ DbgPrint("Instance: (%d)%d\n", slave->pid, slave->loaded_instance);
+ if (slave->loaded_instance == 0 && slave_is_activated(slave)) {
+ slave_set_reactivation(slave, 0);
+ slave_set_reactivate_instances(slave, 0);
+
+ slave = slave_deactivate(slave);
+ }
+
+ return slave;
+}
+
+HAPI const int const slave_is_secured(const struct slave_node *slave)
+{
+ return slave->secured;
+}
+
+HAPI const char * const slave_name(const struct slave_node *slave)
+{
+ return slave->name;
+}
+
+HAPI const char * const slave_abi(const struct slave_node *slave)
+{
+ return slave->abi;
+}
+
+HAPI const pid_t const slave_pid(const struct slave_node *slave)
+{
+ return slave->pid;
+}
+
+HAPI int slave_set_pid(struct slave_node *slave, pid_t pid)
+{
+ if (!slave)
+ return -EINVAL;
+
+ DbgPrint("Slave PID is updated to %d from %d\n", pid, slave->pid);
+
+ slave->pid = pid;
+ return 0;
+}
+
+static inline void invoke_resumed_cb(struct slave_node *slave)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct event *event;
+ int ret;
+
+ EINA_LIST_FOREACH_SAFE(slave->event_resume_list, l, n, event) {
+ ret = event->evt_cb(event->slave, event->cbdata);
+ if (ret < 0) {
+ if (eina_list_data_find(slave->event_resume_list, event)) {
+ slave->event_resume_list = eina_list_remove(slave->event_resume_list, event);
+ DbgFree(event);
+ }
+ }
+ }
+}
+
+static void resume_cb(struct slave_node *slave, const struct packet *packet, void *data)
+{
+ int ret;
+
+ if (slave->state == SLAVE_REQUEST_TO_TERMINATE) {
+ DbgPrint("Slave is terminating now. ignore resume result\n");
+ return;
+ }
+
+ if (!packet) {
+ ErrPrint("Failed to change the state of the slave\n");
+ slave->state = SLAVE_PAUSED;
+ return;
+ }
+
+ if (packet_get(packet, "i", &ret) != 1) {
+ ErrPrint("Invalid parameter\n");
+ return;
+ }
+
+ if (ret == 0) {
+ slave->state = SLAVE_RESUMED;
+ slave_rpc_ping_thaw(slave);
+ invoke_resumed_cb(slave);
+ }
+}
+
+static inline void invoke_paused_cb(struct slave_node *slave)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct event *event;
+ int ret;
+
+ EINA_LIST_FOREACH_SAFE(slave->event_pause_list, l, n, event) {
+ ret = event->evt_cb(event->slave, event->cbdata);
+ if (ret < 0) {
+ if (eina_list_data_find(slave->event_pause_list, event)) {
+ slave->event_pause_list = eina_list_remove(slave->event_pause_list, event);
+ DbgFree(event);
+ }
+ }
+ }
+}
+
+static void pause_cb(struct slave_node *slave, const struct packet *packet, void *data)
+{
+ int ret;
+
+ if (slave->state == SLAVE_REQUEST_TO_TERMINATE) {
+ DbgPrint("Slave is terminating now. ignore pause result\n");
+ return;
+ }
+
+ if (!packet) {
+ ErrPrint("Failed to change the state of the slave\n");
+ slave->state = SLAVE_RESUMED;
+ return;
+ }
+
+ if (packet_get(packet, "i", &ret) != 1) {
+ ErrPrint("Invalid parameter\n");
+ return;
+ }
+
+ if (ret == 0) {
+ slave->state = SLAVE_PAUSED;
+ slave_rpc_ping_freeze(slave);
+ invoke_paused_cb(slave);
+ }
+}
+
+HAPI int slave_resume(struct slave_node *slave)
+{
+ double timestamp;
+ struct packet *packet;
+
+ switch (slave->state) {
+ case SLAVE_REQUEST_TO_LAUNCH:
+ case SLAVE_REQUEST_TO_TERMINATE:
+ case SLAVE_TERMINATED:
+ return -EINVAL;
+ case SLAVE_RESUMED:
+ case SLAVE_REQUEST_TO_RESUME:
+ return 0;
+ default:
+ break;
+ }
+
+ timestamp = util_timestamp();
+
+ packet = packet_create("resume", "d", timestamp);
+ if (!packet) {
+ ErrPrint("Failed to prepare param\n");
+ return -EFAULT;
+ }
+
+ slave->state = SLAVE_REQUEST_TO_RESUME;
+ return slave_rpc_async_request(slave, NULL, packet, resume_cb, NULL, 0);
+}
+
+HAPI int slave_pause(struct slave_node *slave)
+{
+ double timestamp;
+ struct packet *packet;
+
+ switch (slave->state) {
+ case SLAVE_REQUEST_TO_LAUNCH:
+ case SLAVE_REQUEST_TO_TERMINATE:
+ case SLAVE_TERMINATED:
+ return -EINVAL;
+ case SLAVE_PAUSED:
+ case SLAVE_REQUEST_TO_PAUSE:
+ return 0;
+ default:
+ break;
+ }
+
+ timestamp = util_timestamp();
+
+ packet = packet_create("pause", "d", timestamp);
+ if (!packet) {
+ ErrPrint("Failed to prepare param\n");
+ return -EFAULT;
+ }
+
+ slave->state = SLAVE_REQUEST_TO_PAUSE;
+ return slave_rpc_async_request(slave, NULL, packet, pause_cb, NULL, 0);
+}
+
+HAPI const char *slave_pkgname(const struct slave_node *slave)
+{
+ return slave ? slave->pkgname : NULL;
+}
+
+HAPI enum slave_state slave_state(const struct slave_node *slave)
+{
+ return slave ? slave->state : SLAVE_ERROR;
+}
+
+HAPI const char *slave_state_string(const struct slave_node *slave)
+{
+ switch (slave->state) {
+ case SLAVE_REQUEST_TO_LAUNCH:
+ return "RequestToLaunch";
+ case SLAVE_REQUEST_TO_TERMINATE:
+ return "RequestToTerminate";
+ case SLAVE_TERMINATED:
+ return "Terminated";
+ case SLAVE_REQUEST_TO_PAUSE:
+ return "RequestToPause";
+ case SLAVE_REQUEST_TO_RESUME:
+ return "RequestToResume";
+ case SLAVE_PAUSED:
+ return "Paused";
+ case SLAVE_RESUMED:
+ return "Resumed";
+ case SLAVE_ERROR:
+ return "Error";
+ default:
+ break;
+ }
+
+ return "Unknown";
+}
+
+HAPI const void *slave_list(void)
+{
+ return s_info.slave_list;
+}
+
+HAPI int const slave_fault_count(const struct slave_node *slave)
+{
+ return slave->fault_count;
+}
+
+HAPI double const slave_ttl(const struct slave_node *slave)
+{
+ if (!slave->ttl_timer)
+ return 0.0f;
+
+ return ecore_timer_pending_get(slave->ttl_timer);
+}
+
+HAPI void slave_set_reactivate_instances(struct slave_node *slave, int reactivate)
+{
+ slave->reactivate_instances = reactivate;
+}
+
+HAPI int slave_need_to_reactivate_instances(struct slave_node *slave)
+{
+ return slave->reactivate_instances;
+}
+
+HAPI void slave_set_reactivation(struct slave_node *slave, int flag)
+{
+ slave->reactivate_slave = flag;
+}
+
+HAPI int slave_need_to_reactivate(struct slave_node *slave)
+{
+ return slave->reactivate_slave;
+}
+
+/* End of a file */
diff --git a/src/slave_rpc.c b/src/slave_rpc.c
new file mode 100644
index 0000000..2aa8229
--- /dev/null
+++ b/src/slave_rpc.c
@@ -0,0 +1,640 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h> /* strerror */
+#include <errno.h> /* errno */
+#include <unistd.h> /* pid_t */
+#include <stdlib.h> /* free */
+
+#include <Eina.h>
+#include <Ecore.h>
+
+#include <dlog.h>
+
+#include <packet.h>
+#include <com-core_packet.h>
+
+#include "debug.h"
+#include "slave_life.h"
+#include "slave_rpc.h"
+#include "client_life.h"
+#include "package.h"
+#include "fault_manager.h"
+#include "util.h"
+#include "conf.h"
+
+struct slave_rpc {
+ Ecore_Timer *pong_timer;
+ int handle;
+
+ unsigned long ping_count;
+ unsigned long next_ping_count;
+ Eina_List *pending_list;
+};
+
+struct command {
+ /* create_command, destroy_command will care these varaibles */
+ char *pkgname;
+ struct packet *packet;
+ struct slave_node *slave;
+ int ttl; /* If it fails to handle this, destroy this */
+
+ /* Don't need to care these data */
+ void (*ret_cb)(struct slave_node *slave, const struct packet *packet, void *cbdata);
+ void *cbdata;
+};
+
+static struct info {
+ Eina_List *command_list;
+ Ecore_Timer *command_consuming_timer;
+} s_info = {
+ .command_list = NULL,
+ .command_consuming_timer = NULL,
+};
+
+#define DEFAULT_CMD_TTL 3
+
+static inline void prepend_command(struct command *command);
+
+static inline struct command *create_command(struct slave_node *slave, const char *pkgname, struct packet *packet)
+{
+ struct command *command;
+
+ command = calloc(1, sizeof(*command));
+ if (!command) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ if (pkgname) {
+ command->pkgname = strdup(pkgname);
+ if (!command->pkgname) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(command);
+ return NULL;
+ }
+ }
+
+ command->slave = slave_ref(slave); /*!< To prevent from destroying of the slave while communicating with the slave */
+ command->packet = packet_ref(packet);
+ command->ttl = DEFAULT_CMD_TTL;
+
+ return command;
+}
+
+static inline void destroy_command(struct command *command)
+{
+ slave_unref(command->slave);
+ packet_unref(command->packet);
+ DbgFree(command->pkgname);
+ DbgFree(command);
+}
+
+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 int slave_async_cb(pid_t pid, int handle, const struct packet *packet, void *data)
+{
+ struct command *command = data;
+
+ if (!command) {
+ ErrPrint("Packet is NIL\n");
+ return 0;
+ }
+
+ /*!
+ * \note
+ * command->packet is not valid from here.
+ */
+ if (!slave_is_activated(command->slave)) {
+ ErrPrint("Slave is not activated (accidently dead)\n");
+ if (command->ret_cb)
+ command->ret_cb(command->slave, packet, command->cbdata);
+
+ goto out;
+ }
+
+ if (!packet) {
+ DbgPrint("packet == NULL\n");
+ if (command->ret_cb)
+ command->ret_cb(command->slave, packet, command->cbdata);
+
+ command->slave = slave_deactivated_by_fault(command->slave);
+ goto out;
+ }
+
+ if (command->ret_cb)
+ command->ret_cb(command->slave, packet, command->cbdata);
+
+out:
+ destroy_command(command);
+ return 0;
+}
+
+static Eina_Bool command_consumer_cb(void *data)
+{
+ struct command *command;
+ struct slave_rpc *rpc;
+
+ command = pop_command();
+ if (!command) {
+ s_info.command_consuming_timer = NULL;
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ if (!slave_is_activated(command->slave)) {
+ ErrPrint("Slave is not activated: %s(%d)\n",
+ slave_name(command->slave), slave_pid(command->slave));
+ goto errout;
+ }
+
+ if (command->pkgname) {
+ struct pkg_info *info;
+
+ info = package_find(command->pkgname);
+ if (info && package_is_fault(info)) {
+ ErrPrint("info: %p (%s) is fault package\n", info, command->pkgname);
+ goto errout;
+ }
+ }
+
+ rpc = slave_data(command->slave, "rpc");
+ if (!rpc || rpc->handle < 0) {
+ ErrPrint("Slave has no rpc info\n");
+ goto errout;
+ }
+
+ if (packet_type(command->packet) == PACKET_REQ_NOACK) {
+ if (com_core_packet_send_only(rpc->handle, command->packet) == 0) {
+ /* Keep a slave alive, while processing events */
+ slave_give_more_ttl(command->slave);
+ destroy_command(command);
+ return ECORE_CALLBACK_RENEW;
+ }
+ } else if (packet_type(command->packet) == PACKET_REQ) {
+ if (com_core_packet_async_send(rpc->handle, command->packet, 0.0f, slave_async_cb, command) == 0) {
+ /* Keep a slave alive, while processing events */
+ slave_give_more_ttl(command->slave);
+ return ECORE_CALLBACK_RENEW;
+ }
+ }
+
+ /*!
+ * \WARN
+ * What happens at here?
+ * We are failed to send a packet!!!
+ * Let's try to send this again
+ */
+ /*!
+ * \todo
+ * Do we need to handle this error?
+ * Close current connection and make new one?
+ * how about pended command lists?
+ */
+ DbgPrint("Packet type: %d\n", packet_type(command->packet));
+ DbgPrint("Packet: %p\n", command->packet);
+ DbgPrint("Handle: %d\n", rpc->handle);
+ DbgPrint("PID: %d\n", slave_pid(command->slave));
+ DbgPrint("Name: %s\n", slave_name(command->slave));
+ DbgPrint("Package: %s\n", command->pkgname);
+ command->ttl--;
+ if (command->ttl == 0) {
+ DbgPrint("Discard packet (%d)\n", command->ttl);
+ destroy_command(command);
+ } else {
+ DbgPrint("Send again (%d)\n", command->ttl);
+ prepend_command(command);
+ }
+ return ECORE_CALLBACK_RENEW;
+
+errout:
+ if (command->ret_cb)
+ command->ret_cb(command->slave, NULL, command->cbdata);
+
+ destroy_command(command);
+ return ECORE_CALLBACK_RENEW;
+}
+
+static inline void prepend_command(struct command *command)
+{
+ s_info.command_list = eina_list_prepend(s_info.command_list, command);
+
+ if (s_info.command_consuming_timer)
+ return;
+
+ s_info.command_consuming_timer = ecore_timer_add(PACKET_TIME, command_consumer_cb, NULL);
+ if (!s_info.command_consuming_timer) {
+ ErrPrint("Failed to add command consumer\n");
+ s_info.command_list = eina_list_remove(s_info.command_list, command);
+ destroy_command(command);
+ }
+}
+
+static inline void push_command(struct command *command)
+{
+ s_info.command_list = eina_list_append(s_info.command_list, command);
+
+ if (s_info.command_consuming_timer)
+ return;
+
+ s_info.command_consuming_timer = ecore_timer_add(PACKET_TIME, command_consumer_cb, NULL);
+ if (!s_info.command_consuming_timer) {
+ ErrPrint("Failed to add command consumer\n");
+ s_info.command_list = eina_list_remove(s_info.command_list, command);
+ destroy_command(command);
+ }
+}
+
+static int slave_deactivate_cb(struct slave_node *slave, void *data)
+{
+ struct slave_rpc *rpc;
+ struct command *command;
+ Eina_List *l;
+ Eina_List *n;
+
+ rpc = slave_data(slave, "rpc");
+ if (!rpc) {
+ /*!
+ * \note
+ * Return negative value will remove this callback from the event list of the slave
+ */
+ return -EINVAL;
+ }
+
+ if (rpc->pong_timer) {
+ ecore_timer_del(rpc->pong_timer);
+ rpc->pong_timer = NULL;
+ } else {
+ ErrPrint("slave has no pong timer\n");
+ }
+
+ EINA_LIST_FOREACH_SAFE(s_info.command_list, l, n, command) {
+ if (command->slave == slave) {
+ s_info.command_list = eina_list_remove(s_info.command_list, command);
+ destroy_command(command);
+ }
+ }
+
+ /*!
+ * \note
+ * Reset handle
+ */
+ DbgPrint("Reset handle for %d\n", slave_pid(slave));
+ rpc->handle = -1;
+
+ /*!
+ * \todo
+ * Make statistics table
+ */
+ rpc->ping_count = 0;
+ rpc->next_ping_count = 1;
+ return 0;
+}
+
+static Eina_Bool ping_timeout_cb(void *data)
+{
+ struct slave_rpc *rpc;
+ struct slave_node *slave = data;
+
+ rpc = slave_data(slave, "rpc");
+ if (!rpc) {
+ ErrPrint("Slave RPC is not valid (%s)\n", slave_name(slave));
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ /*!
+ * \note
+ * Clear the pong_timer
+ */
+ rpc->pong_timer = NULL;
+
+ if (!slave_is_activated(slave)) {
+ ErrPrint("Slave is not activated (%s)\n", slave_name(slave));
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ /*!
+ * Dead callback will handling this
+ */
+ DbgPrint("Slave PING TIMEOUT: %s(%d)\n", slave_name(slave), slave_pid(slave));
+ slave = slave_deactivated_by_fault(slave);
+ DbgPrint("Slave(%p)\n", slave);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+HAPI 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)
+{
+ struct command *command;
+ struct slave_rpc *rpc;
+
+ command = create_command(slave, pkgname, packet);
+ if (!command) {
+ ErrPrint("Failed to create command\n");
+
+ if (ret_cb)
+ ret_cb(slave, NULL, data);
+
+ packet_unref(packet);
+ return -ENOMEM;
+ }
+
+ command->ret_cb = ret_cb;
+ command->cbdata = data;
+ packet_unref(packet);
+
+ rpc = slave_data(slave, "rpc");
+ if (!rpc) {
+ ErrPrint("Slave has no RPC\n");
+ if (ret_cb)
+ ret_cb(slave, NULL, data);
+ destroy_command(command);
+ return -EFAULT;
+ }
+
+ if (rpc->handle < 0) {
+ DbgPrint("RPC handle is not ready to use it\n");
+ if (slave_is_secured(slave) && !slave_is_activated(slave)) {
+ int ret;
+ DbgPrint("Activate slave forcely\n");
+ ret = slave_activate(slave);
+ if (ret < 0 && ret != -EALREADY) {
+
+ if (ret_cb)
+ ret_cb(slave, NULL, data);
+
+ destroy_command(command);
+ return ret;
+ }
+ }
+
+ if (urgent)
+ rpc->pending_list = eina_list_prepend(rpc->pending_list, command);
+ else
+ rpc->pending_list = eina_list_append(rpc->pending_list, command);
+
+ return 0;
+ }
+
+ if (urgent)
+ prepend_command(command);
+ else
+ push_command(command);
+
+ return 0;
+}
+
+HAPI int slave_rpc_request_only(struct slave_node *slave, const char *pkgname, struct packet *packet, int urgent)
+{
+ struct command *command;
+ struct slave_rpc *rpc;
+
+ command = create_command(slave, pkgname, packet);
+ if (!command) {
+ ErrPrint("Failed to create a command\n");
+ packet_unref(packet);
+ return -ENOMEM;
+ }
+
+ command->ret_cb = NULL;
+ command->cbdata = NULL;
+ packet_unref(packet);
+
+ rpc = slave_data(slave, "rpc");
+ if (!rpc) {
+ ErrPrint("Slave has no RPC\n");
+ destroy_command(command);
+ return -EFAULT;
+ }
+
+ if (rpc->handle < 0) {
+ DbgPrint("RPC handle is not ready to use it\n");
+
+ if (slave_is_secured(slave) && !slave_is_activated(slave)) {
+ int ret;
+
+ DbgPrint("Activate slave forcely\n");
+ ret = slave_activate(slave);
+ if (ret < 0 && ret != -EALREADY) {
+ destroy_command(command);
+ return ret;
+ }
+ }
+
+ if (urgent)
+ rpc->pending_list = eina_list_prepend(rpc->pending_list, command);
+ else
+ rpc->pending_list = eina_list_append(rpc->pending_list, command);
+
+ return 0;
+ }
+
+ if (urgent)
+ prepend_command(command);
+ else
+ push_command(command);
+
+ return 0;
+}
+
+HAPI int slave_rpc_update_handle(struct slave_node *slave, int handle)
+{
+ struct slave_rpc *rpc;
+ struct command *command;
+
+ rpc = slave_data(slave, "rpc");
+ if (!rpc)
+ return -EINVAL;
+
+ DbgPrint("SLAVE: New handle assigned for %d, %d\n", slave_pid(slave), handle);
+ rpc->handle = handle;
+ if (rpc->pong_timer)
+ ecore_timer_del(rpc->pong_timer);
+
+ rpc->pong_timer = ecore_timer_add(DEFAULT_PING_TIME, ping_timeout_cb, slave);
+ if (!rpc->pong_timer)
+ ErrPrint("Failed to add ping timer\n");
+
+ /*!
+ * \note
+ * slave_activated will call the activated callback.
+ * activated callback will try to recover the normal instances state.
+ * so the reset_fault should be called after slave_activated function.
+ */
+ slave_activated(slave);
+
+ EINA_LIST_FREE(rpc->pending_list, command) {
+ push_command(command);
+ }
+
+ return 0;
+}
+
+HAPI int slave_rpc_init(struct slave_node *slave)
+{
+ struct slave_rpc *rpc;
+
+ rpc = calloc(1, sizeof(*rpc));
+ if (!rpc) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ if (slave_set_data(slave, "rpc", rpc) < 0) {
+ DbgFree(rpc);
+ return -ENOMEM;
+ }
+
+ slave_event_callback_add(slave, SLAVE_EVENT_DEACTIVATE, slave_deactivate_cb, NULL);
+
+ rpc->ping_count = 0;
+ rpc->next_ping_count = 1;
+ rpc->handle = -1;
+
+ return 0;
+}
+
+HAPI int slave_rpc_fini(struct slave_node *slave)
+{
+ struct slave_rpc *rpc;
+
+ rpc = slave_del_data(slave, "rpc");
+ if (!rpc)
+ return -EINVAL;
+
+ slave_event_callback_del(slave, SLAVE_EVENT_DEACTIVATE, slave_deactivate_cb, NULL);
+
+ if (rpc->pong_timer)
+ ecore_timer_del(rpc->pong_timer);
+
+ DbgFree(rpc);
+ return 0;
+}
+
+HAPI int slave_rpc_ping(struct slave_node *slave)
+{
+ struct slave_rpc *rpc;
+
+ rpc = slave_data(slave, "rpc");
+ if (!rpc) {
+ ErrPrint("Slave RPC is not valid\n");
+ return -EINVAL;
+ }
+
+ if (!slave_is_activated(slave)) {
+ ErrPrint("Slave is not activated\n");
+ return -EFAULT;
+ }
+
+ rpc->ping_count++;
+ if (rpc->ping_count != rpc->next_ping_count) {
+ ErrPrint("Ping count is not correct\n");
+ rpc->next_ping_count = rpc->ping_count;
+ }
+ rpc->next_ping_count++;
+
+ ecore_timer_reset(rpc->pong_timer);
+ return 0;
+}
+
+HAPI int slave_rpc_ping_freeze(struct slave_node *slave)
+{
+ struct slave_rpc *rpc;
+
+ rpc = slave_data(slave, "rpc");
+ if (!rpc) {
+ ErrPrint("Slave RPC is not valid\n");
+ return -EINVAL;
+ }
+
+ if (!slave_is_activated(slave)) {
+ ErrPrint("Slave is not activated\n");
+ return -EFAULT;
+ }
+
+ ecore_timer_freeze(rpc->pong_timer);
+ return 0;
+}
+
+HAPI int slave_rpc_ping_thaw(struct slave_node *slave)
+{
+ struct slave_rpc *rpc;
+
+ rpc = slave_data(slave, "rpc");
+ if (!rpc) {
+ ErrPrint("Slave RPC is not valid\n");
+ return -EINVAL;
+ }
+
+ if (!slave_is_activated(slave)) {
+ ErrPrint("Slave is not activated\n");
+ return -EFAULT;
+ }
+
+ ecore_timer_thaw(rpc->pong_timer);
+ return 0;
+}
+
+HAPI void slave_rpc_request_update(const char *pkgname, const char *id, const char *cluster, const char *category)
+{
+ struct slave_node *slave;
+ struct pkg_info *info;
+ struct packet *packet;
+
+ info = package_find(pkgname);
+ if (!info) {
+ ErrPrint("Failed to find a package\n");
+ return;
+ }
+
+ slave = package_slave(info);
+ if (!slave) {
+ ErrPrint("Failed to find a slave for %s\n", pkgname);
+ return;
+ }
+
+ packet = packet_create_noack("update_content", "ssss", pkgname, id, cluster, category);
+ if (!packet) {
+ ErrPrint("Failed to create a new param\n");
+ return;
+ }
+
+ (void)slave_rpc_request_only(slave, pkgname, packet, 0);
+}
+
+HAPI int slave_rpc_handle(struct slave_node *slave)
+{
+ struct slave_rpc *rpc;
+
+ rpc = slave_data(slave, "rpc");
+ if (!rpc) {
+ DbgPrint("Slave RPC is not initiated\n");
+ return -EINVAL;
+ }
+
+ return rpc->handle;
+}
+
+/* End of a file */
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..28c042d
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <ctype.h>
+
+#include <dlog.h>
+#include <Eina.h>
+#include <Ecore.h>
+
+#include "util.h"
+#include "debug.h"
+#include "conf.h"
+
+int errno;
+
+HAPI unsigned long util_string_hash(const char *str)
+{
+ unsigned long ret = 0;
+
+ while (*str)
+ ret += (unsigned long)(*str++);
+
+ ret %= 371773;
+ return ret;
+}
+
+HAPI double util_timestamp(void)
+{
+ struct timeval tv;
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ static unsigned long internal_count = 0;
+ ErrPrint("failed to get time of day: %s\n", strerror(errno));
+ tv.tv_sec = internal_count++;
+ tv.tv_usec = 0;
+ }
+
+ return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f;
+}
+
+HAPI int util_check_ext(const char *filename, const char *check_ptr)
+{
+ int name_len;
+
+ name_len = strlen(filename);
+ while (--name_len >= 0 && *check_ptr) {
+ if (filename[name_len] != *check_ptr)
+ return -EINVAL;
+
+ check_ptr ++;
+ }
+
+ return 0;
+}
+
+static inline int check_native_livebox(const char *pkgname)
+{
+ int len;
+ char *path;
+
+ len = strlen(pkgname) * 2;
+ len += strlen(ROOT_PATH);
+ len += strlen("%s/libexec/liblive-%s.so");
+
+ path = malloc(len + 1);
+ if (!path) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ snprintf(path, len, "%s%s/libexec/liblive-%s.so", ROOT_PATH, pkgname, pkgname);
+ if (access(path, F_OK | R_OK) != 0) {
+ ErrPrint("%s is not a valid package\n", pkgname);
+ DbgFree(path);
+ return -EINVAL;
+ }
+
+ DbgFree(path);
+ return 0;
+}
+
+static inline int check_web_livebox(const char *pkgname)
+{
+ int len;
+ char *path;
+
+ len = strlen(pkgname) * 2;
+ len += strlen("/opt/usr/apps/%s/res/wgt/livebox/index.html");
+
+ path = malloc(len + 1);
+ if (!path) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ snprintf(path, len, "/opt/usr/apps/%s/res/wgt/livebox/index.html", pkgname);
+ if (access(path, F_OK | R_OK) != 0) {
+ ErrPrint("%s is not a valid package\n", pkgname);
+ DbgFree(path);
+ return -EINVAL;
+ }
+
+ DbgFree(path);
+ return 0;
+}
+
+HAPI int util_validate_livebox_package(const char *pkgname)
+{
+ if (!pkgname) {
+ ErrPrint("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ if (!check_native_livebox(pkgname) || !check_web_livebox(pkgname))
+ return 0;
+
+ return -EINVAL;
+}
+
+HAPI int util_unlink(const char *filename)
+{
+ char *descfile;
+ int desclen;
+ int ret;
+
+ desclen = strlen(filename) + 6; /* .desc */
+ descfile = malloc(desclen);
+ if (!descfile) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ ret = snprintf(descfile, desclen, "%s.desc", filename);
+ if (ret < 0) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ DbgFree(descfile);
+ return -EFAULT;
+ }
+
+ (void)unlink(descfile);
+ DbgFree(descfile);
+ (void)unlink(filename);
+
+ return 0;
+}
+
+HAPI char *util_slavename(void)
+{
+ char slavename[BUFSIZ];
+ static unsigned long idx = 0;
+
+ snprintf(slavename, sizeof(slavename), "%lu_%lf", idx++, util_timestamp());
+ return strdup(slavename);
+}
+
+HAPI const char *util_basename(const char *name)
+{
+ int length;
+ length = name ? strlen(name) : 0;
+ if (!length)
+ return ".";
+
+ while (--length > 0 && name[length] != '/');
+
+ return length <= 0 ? name : (name + length + (name[length] == '/'));
+}
+
+HAPI unsigned long util_free_space(const char *path)
+{
+ struct statvfs st;
+ unsigned long space;
+
+ if (statvfs(path, &st) < 0) {
+ ErrPrint("statvfs: %s\n", strerror(errno));
+ return 0lu;
+ }
+
+ space = st.f_bsize * st.f_bfree;
+ /*!
+ * \note
+ * Must have to check the overflow
+ */
+ return space;
+}
+
+static inline char *extend_heap(char *buffer, int *sz, int incsz)
+{
+ char *tmp;
+
+ *sz += incsz;
+ tmp = realloc(buffer, *sz);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ return tmp;
+}
+
+
+HAPI char *util_replace_string(const char *src, const char *pattern, const char *replace)
+{
+ const char *ptr;
+ char *tmp;
+ char *ret = NULL;
+ int idx;
+ int out_idx;
+ int out_sz;
+ enum {
+ STATE_START,
+ STATE_FIND,
+ STATE_CHECK,
+ STATE_END,
+ } state;
+
+ if (!src || !pattern)
+ return NULL;
+
+ out_sz = strlen(src);
+ ret = strdup(src);
+ if (!ret) {
+ printf("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ out_idx = 0;
+ for (state = STATE_START, ptr = src; state != STATE_END; ptr++) {
+ switch (state) {
+ case STATE_START:
+ if (*ptr == '\0') {
+ state = STATE_END;
+ } else if (!isblank(*ptr)) {
+ state = STATE_FIND;
+ ptr--;
+ }
+ break;
+ case STATE_FIND:
+ if (*ptr == '\0') {
+ state = STATE_END;
+ } else if (*ptr == *pattern) {
+ state = STATE_CHECK;
+ ptr--;
+ idx = 0;
+ } else {
+ ret[out_idx] = *ptr;
+ out_idx++;
+ if (out_idx == out_sz) {
+ tmp = extend_heap(ret, &out_sz, strlen(replace) + 1);
+ if (!tmp) {
+ free(ret);
+ return NULL;
+ }
+ ret = tmp;
+ }
+ }
+ break;
+ case STATE_CHECK:
+ if (!pattern[idx]) {
+ /*!
+ * If there is no space for copying the replacement,
+ * Extend size of the return buffer.
+ */
+ if (out_sz - out_idx < strlen(replace) + 1) {
+ tmp = extend_heap(ret, &out_sz, strlen(replace) + 1);
+ if (!tmp) {
+ free(ret);
+ return NULL;
+ }
+ ret = tmp;
+ }
+
+ strcpy(ret + out_idx, replace);
+ out_idx += strlen(replace);
+
+ state = STATE_FIND;
+ ptr--;
+ } else if (*ptr != pattern[idx]) {
+ ptr -= idx;
+
+ /* Copy the first matched character */
+ ret[out_idx] = *ptr;
+ out_idx++;
+ if (out_idx == out_sz) {
+ tmp = extend_heap(ret, &out_sz, strlen(replace) + 1);
+ if (!tmp) {
+ free(ret);
+ return NULL;
+ }
+
+ ret = tmp;
+ }
+
+ state = STATE_FIND;
+ } else {
+ idx++;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return ret;
+}
+
+
+HAPI const char *util_uri_to_path(const char *uri)
+{
+ int len;
+
+ len = strlen(SCHEMA_FILE);
+ if (strncasecmp(uri, SCHEMA_FILE, len))
+ return NULL;
+
+ return uri + len;
+}
+
+HAPI double util_time_delay_for_compensation(double period)
+{
+ struct timeval tv;
+ unsigned long long curtime;
+ unsigned long long _period;
+ unsigned long long remain;
+ unsigned int sec;
+ unsigned int usec;
+ double ret;
+
+ gettimeofday(&tv, NULL);
+ curtime = (unsigned long long)tv.tv_sec * 1000000llu + (unsigned long long)tv.tv_usec;
+
+ sec = (unsigned int)period;
+ usec = (period - sec) * 1000000;
+ _period = (unsigned long long)sec * 1000000llu + usec;
+
+ remain = curtime % _period;
+
+ sec = (unsigned int)(remain / 1000000llu);
+ usec = (unsigned int)(remain % 1000000llu);
+
+ ret = (double)sec + (double)usec / 1000000.0f;
+ return period - ret;
+}
+
+HAPI void *util_timer_add(double interval, Eina_Bool (*cb)(void *data), void *data)
+{
+ Ecore_Timer *timer;
+ double delay;
+
+ timer = ecore_timer_add(interval, cb, data);
+ if (!timer)
+ return NULL;
+
+ delay = util_time_delay_for_compensation(interval) - interval;
+ ecore_timer_delay(timer, delay);
+ DbgPrint("Compensate timer: %lf\n", delay);
+
+ return timer;
+}
+
+HAPI void util_timer_interval_set(void *timer, double interval)
+{
+ double delay;
+ ecore_timer_interval_set(timer, interval);
+
+ delay = util_time_delay_for_compensation(interval) - interval;
+ ecore_timer_delay(timer, delay);
+}
+
+HAPI char *util_get_file_kept_in_safe(const char *id)
+{
+ const char *path;
+ char *new_path;
+ int len;
+ int base_idx;
+
+ path = util_uri_to_path(id);
+ if (!path) {
+ ErrPrint("Invalid URI(%s)\n", id);
+ return NULL;
+ }
+
+ /*!
+ * TODO: Remove me
+ */
+ if (OVERWRITE_CONTENT)
+ return strdup(path);
+
+ len = strlen(path);
+ base_idx = len - 1;
+
+ while (base_idx > 0 && path[base_idx] != '/') base_idx--;
+ base_idx += (path[base_idx] == '/');
+
+ new_path = malloc(len + 10);
+ if (!new_path) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ strncpy(new_path, path, base_idx);
+ snprintf(new_path + base_idx, len + 10 - base_idx, "reader/%s", path + base_idx);
+ return new_path;
+}
+
+HAPI int util_unlink_files(const char *folder)
+{
+ struct stat info;
+ DIR *handle;
+ struct dirent *entry;
+ char *abspath;
+ int len;
+
+ if (lstat(folder, &info) < 0) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ return -EIO;
+ }
+
+ if (!S_ISDIR(info.st_mode)) {
+ ErrPrint("Error: %s is not a folder", folder);
+ return -EINVAL;
+ }
+
+ handle = opendir(folder);
+ if (!handle) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ return -EIO;
+ }
+
+ while ((entry = readdir(handle))) {
+ if (!strcmp(entry->d_name, "."))
+ continue;
+
+ if (!strcmp(entry->d_name, ".."))
+ continue;
+
+ len = strlen(folder) + strlen(entry->d_name) + 3;
+ abspath = calloc(1, len);
+ if (!abspath) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ continue;
+ }
+ snprintf(abspath, len - 1, "%s/%s", folder, entry->d_name);
+
+ if (unlink(abspath) < 0)
+ DbgPrint("unlink: %s - %s\n", abspath, strerror(errno));
+
+ free(abspath);
+ }
+
+ closedir(handle);
+ return 0;
+}
+
+/* End of a file */
diff --git a/src/xmonitor.c b/src/xmonitor.c
new file mode 100644
index 0000000..2260133
--- /dev/null
+++ b/src/xmonitor.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <assert.h>
+#include <errno.h>
+#include <malloc.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <Evas.h>
+#include <Ecore_X.h>
+#include <Ecore.h>
+
+#include <sqlite3.h>
+
+#include <gio/gio.h>
+#include <dlog.h>
+
+#include "conf.h"
+#include "debug.h"
+#include "client_life.h"
+#include "slave_life.h"
+#include "main.h"
+#include "util.h"
+#include "setting.h"
+#include "xmonitor.h"
+
+int errno;
+
+struct event_item {
+ int (*cb)(void *user_data);
+ void *user_data;
+};
+
+static struct info {
+ Ecore_Event_Handler *create_handler;
+ Ecore_Event_Handler *destroy_handler;
+ Ecore_Event_Handler *client_handler;
+
+ Eina_List *pause_list;
+ Eina_List *resume_list;
+
+ int paused;
+} s_info = {
+ .create_handler = NULL,
+ .destroy_handler = NULL,
+ .client_handler = NULL,
+
+ .pause_list = NULL,
+ .resume_list = NULL,
+
+ .paused = 1, /*!< The provider is treated as paused process when it is launched */
+};
+
+static inline void touch_paused_file(void)
+{
+ int fd;
+ fd = creat(PAUSED_FILE, 0644);
+ if (fd >= 0)
+ close(fd);
+ else
+ ErrPrint("Create .live.paused: %s\n", strerror(errno));
+}
+
+static inline void remove_paused_file(void)
+{
+ if (unlink(PAUSED_FILE) < 0)
+ ErrPrint("Unlink .live.paused: %s\n", strerror(errno));
+}
+
+static inline int get_pid(Ecore_X_Window win)
+{
+ int pid;
+ Ecore_X_Atom atom;
+ unsigned char *in_pid;
+ int num;
+
+ atom = ecore_x_atom_get("X_CLIENT_PID");
+ if (ecore_x_window_prop_property_get(win, atom, ECORE_X_ATOM_CARDINAL,
+ sizeof(int), &in_pid, &num) == EINA_FALSE) {
+ if (ecore_x_netwm_pid_get(win, &pid) == EINA_FALSE) {
+ ErrPrint("Failed to get PID from a window 0x%X\n", win);
+ return -EINVAL;
+ }
+ } else if (in_pid) {
+ pid = *(int *)in_pid;
+ DbgFree(in_pid);
+ } else {
+ ErrPrint("Failed to get PID\n");
+ return -EINVAL;
+ }
+
+ return pid;
+}
+
+static Eina_Bool create_cb(void *data, int type, void *event)
+{
+ Ecore_X_Event_Window_Create *info = event;
+ ecore_x_window_client_sniff(info->win);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool destroy_cb(void *data, int type, void *event)
+{
+ // Ecore_X_Event_Window_Destroy *info = event;
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+HAPI void xmonitor_handle_state_changes(void)
+{
+ int paused;
+ Eina_List *l;
+ struct event_item *item;
+
+ paused = client_is_all_paused() || setting_is_lcd_off();
+ if (s_info.paused == paused)
+ return;
+
+ s_info.paused = paused;
+
+ if (s_info.paused) {
+ EINA_LIST_FOREACH(s_info.pause_list, l, item) {
+ if (item->cb)
+ item->cb(item->user_data);
+ }
+
+ touch_paused_file();
+
+ sqlite3_release_memory(SQLITE_FLUSH_MAX);
+ malloc_trim(0);
+ } else {
+ remove_paused_file();
+
+ EINA_LIST_FOREACH(s_info.resume_list, l, item) {
+ if (item->cb)
+ item->cb(item->user_data);
+ }
+ }
+}
+
+HAPI int xmonitor_update_state(int target_pid)
+{
+ Ecore_X_Window win;
+ struct client_node *client;
+ int pid;
+
+ if (!USE_XMONITOR)
+ return 0;
+
+ win = ecore_x_window_focus_get();
+
+ pid = get_pid(win);
+ if (pid <= 0) {
+ DbgPrint("Focused window has no PID %X\n", win);
+ client = client_find_by_pid(target_pid);
+ if (client) {
+ DbgPrint("Client window has no focus now\n");
+ client_paused(client);
+ }
+ return -ENOENT;
+ }
+
+ client = client_find_by_pid(pid);
+ if (!client) {
+ DbgPrint("Client %d is not registered yet\n", pid);
+ client = client_find_by_pid(target_pid);
+ if (client) {
+ DbgPrint("Client window has no focus now\n");
+ client_paused(client);
+ }
+ return -EINVAL;
+ }
+
+ if (target_pid != pid) {
+ DbgPrint("Client is paused\n");
+ client_paused(client);
+ } else {
+ DbgPrint("Client is resumed\n");
+ client_resumed(client);
+ }
+
+ xmonitor_handle_state_changes();
+ return 0;
+}
+
+static Eina_Bool client_cb(void *data, int type, void *event)
+{
+ Ecore_X_Event_Client_Message *info = event;
+ struct client_node *client;
+ char *name;
+ int pid;
+
+ pid = get_pid(info->win);
+ if (pid <= 0)
+ return ECORE_CALLBACK_PASS_ON;
+
+ client = client_find_by_pid(pid);
+ if (!client)
+ return ECORE_CALLBACK_PASS_ON;
+
+ name = ecore_x_atom_name_get(info->message_type);
+ if (!name)
+ return ECORE_CALLBACK_PASS_ON;
+
+ if (!strcmp(name, "_X_ILLUME_DEACTIVATE_WINDOW")) {
+ DbgPrint("PAUSE EVENT\n");
+ xmonitor_pause(client);
+ } else if (!strcmp(name, "_X_ILLUME_ACTIVATE_WINDOW")) {
+ DbgPrint("RESUME EVENT\n");
+ xmonitor_resume(client);
+ } else {
+ /* ignore event */
+ }
+
+ DbgFree(name);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static inline void sniff_all_windows(void)
+{
+ Ecore_X_Window root;
+ Ecore_X_Window ret;
+ struct stack_item *new_item;
+ struct stack_item *item;
+ Eina_List *win_stack;
+ //int pid;
+ struct stack_item {
+ Ecore_X_Window *wins;
+ int nr_of_wins;
+ int i;
+ };
+
+ root = ecore_x_window_root_first_get();
+ ecore_x_window_sniff(root);
+
+ new_item = malloc(sizeof(*new_item));
+ if (!new_item) {
+ ErrPrint("Error(%s)\n", strerror(errno));
+ return;
+ }
+
+ new_item->nr_of_wins = 0;
+ new_item->wins =
+ ecore_x_window_children_get(root, &new_item->nr_of_wins);
+ new_item->i = 0;
+
+ win_stack = NULL;
+
+ if (new_item->wins)
+ win_stack = eina_list_append(win_stack, new_item);
+ else
+ DbgFree(new_item);
+
+ while ((item = eina_list_nth(win_stack, 0))) {
+ win_stack = eina_list_remove(win_stack, item);
+
+ if (!item->wins) {
+ DbgFree(item);
+ continue;
+ }
+
+ while (item->i < item->nr_of_wins) {
+ ret = item->wins[item->i];
+
+ /*
+ * Now we don't need to care about visibility of window,
+ * just check whether it is registered or not.
+ * (ecore_x_window_visible_get(ret))
+ */
+ ecore_x_window_client_sniff(ret);
+
+ new_item = malloc(sizeof(*new_item));
+ if (!new_item) {
+ ErrPrint("Error %s\n", strerror(errno));
+ item->i++;
+ continue;
+ }
+
+ new_item->i = 0;
+ new_item->nr_of_wins = 0;
+ new_item->wins =
+ ecore_x_window_children_get(ret,
+ &new_item->nr_of_wins);
+ if (new_item->wins) {
+ win_stack =
+ eina_list_append(win_stack, new_item);
+ } else {
+ DbgFree(new_item);
+ }
+
+ item->i++;
+ }
+
+ DbgFree(item->wins);
+ DbgFree(item);
+ }
+
+ return;
+}
+
+HAPI int xmonitor_pause(struct client_node *client)
+{
+ DbgPrint("%d is paused\n", client_pid(client));
+ client_paused(client);
+ xmonitor_handle_state_changes();
+ return 0;
+}
+
+HAPI int xmonitor_resume(struct client_node *client)
+{
+ DbgPrint("%d is resumed\n", client_pid(client));
+ client_resumed(client);
+ xmonitor_handle_state_changes();
+ return 0;
+}
+
+static inline void disable_xmonitor(void)
+{
+ ecore_event_handler_del(s_info.create_handler);
+ ecore_event_handler_del(s_info.destroy_handler);
+ ecore_event_handler_del(s_info.client_handler);
+
+ s_info.create_handler = NULL;
+ s_info.destroy_handler = NULL;
+ s_info.client_handler = NULL;
+}
+
+static inline int enable_xmonitor(void)
+{
+ if (ecore_x_composite_query() == EINA_FALSE)
+ DbgPrint("====> COMPOSITOR IS NOT ENABLED\n");
+
+ s_info.create_handler =
+ ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CREATE,
+ create_cb, NULL);
+ if (!s_info.create_handler) {
+ ErrPrint("Failed to add create event handler\n");
+ return -EFAULT;
+ }
+
+ s_info.destroy_handler =
+ ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY,
+ destroy_cb, NULL);
+ if (!s_info.create_handler) {
+ ErrPrint("Failed to add destroy event handler\n");
+ ecore_event_handler_del(s_info.create_handler);
+ s_info.create_handler = NULL;
+ return -EFAULT;
+ }
+
+ s_info.client_handler =
+ ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE,
+ client_cb, NULL);
+ if (!s_info.client_handler) {
+ ErrPrint("Failed to add focus out event handler\n");
+ ecore_event_handler_del(s_info.create_handler);
+ ecore_event_handler_del(s_info.destroy_handler);
+ s_info.create_handler = NULL;
+ s_info.destroy_handler = NULL;
+ return -EFAULT;
+ }
+
+ sniff_all_windows();
+ return 0;
+}
+
+HAPI int xmonitor_init(void)
+{
+ if (USE_XMONITOR) {
+ int ret;
+ ret = enable_xmonitor();
+ if (ret < 0)
+ return ret;
+ }
+
+ s_info.paused = client_is_all_paused() || setting_is_lcd_off();
+ if (s_info.paused) {
+ touch_paused_file();
+ } else {
+ remove_paused_file();
+ }
+ return 0;
+}
+
+HAPI void xmonitor_fini(void)
+{
+ if (USE_XMONITOR)
+ disable_xmonitor();
+}
+
+HAPI int xmonitor_add_event_callback(enum xmonitor_event event, int (*cb)(void *user_data), void *user_data)
+{
+ struct event_item *item;
+
+ item = malloc(sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ item->cb = cb;
+ item->user_data = user_data;
+
+ switch (event) {
+ case XMONITOR_PAUSED:
+ s_info.pause_list = eina_list_prepend(s_info.pause_list, item);
+ break;
+ case XMONITOR_RESUMED:
+ s_info.resume_list = eina_list_prepend(s_info.resume_list, item);
+ break;
+ default:
+ ErrPrint("Invalid event type\n");
+ DbgFree(item);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+HAPI int xmonitor_del_event_callback(enum xmonitor_event event, int (*cb)(void *user_data), void *user_data)
+{
+ struct event_item *item;
+ Eina_List *l;
+ Eina_List *n;
+
+ switch (event) {
+ case XMONITOR_PAUSED:
+ EINA_LIST_FOREACH_SAFE(s_info.pause_list, l, n, item) {
+ if (item->cb == cb && item->user_data == user_data) {
+ s_info.pause_list = eina_list_remove(s_info.pause_list, item);
+ DbgFree(item);
+ return 0;
+ }
+ }
+ break;
+
+ case XMONITOR_RESUMED:
+ EINA_LIST_FOREACH_SAFE(s_info.resume_list, l, n, item) {
+ if (item->cb == cb && item->user_data == user_data) {
+ s_info.resume_list = eina_list_remove(s_info.resume_list, item);
+ DbgFree(item);
+ return 0;
+ }
+ }
+ break;
+ default:
+ ErrPrint("Invalid event type\n");
+ return -EINVAL;
+ }
+
+ return -ENOENT;
+}
+
+HAPI int xmonitor_is_paused(void)
+{
+ return s_info.paused;
+}
+
+/* End of a file */
diff --git a/util_liveinfo/CMakeLists.txt b/util_liveinfo/CMakeLists.txt
new file mode 100644
index 0000000..04089f5
--- /dev/null
+++ b/util_liveinfo/CMakeLists.txt
@@ -0,0 +1,38 @@
+PROJECT(liveinfo C)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/util_liveinfo/include)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(info_pkgs REQUIRED
+ dlog
+ db-util
+ com-core
+ ecore
+ glib-2.0
+ gio-2.0
+ livebox-service
+ xdamage
+ xfixes
+ x11
+ xext
+)
+
+FOREACH(flag ${info_pkgs_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -g -Wall -Werror")
+
+ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"")
+ADD_DEFINITIONS("-DSOCKET_FILE=\"/opt/usr/share/live_magazine/.live.socket\"")
+
+ADD_EXECUTABLE(${PROJECT_NAME}
+ src/liveinfo.c
+ src/node.c
+)
+
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${info_pkgs_LDFLAGS})
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
+
+# End of a file
diff --git a/util_liveinfo/include/liveinfo.h b/util_liveinfo/include/liveinfo.h
new file mode 100644
index 0000000..62077ae
--- /dev/null
+++ b/util_liveinfo/include/liveinfo.h
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+
diff --git a/util_liveinfo/include/node.h b/util_liveinfo/include/node.h
new file mode 100644
index 0000000..812b59e
--- /dev/null
+++ b/util_liveinfo/include/node.h
@@ -0,0 +1,41 @@
+
+enum node_type {
+ NODE_DIR,
+ NODE_FILE,
+ NODE_LINK,
+};
+
+struct node;
+
+#define NODE_READ 0x01
+#define NODE_WRITE 0x02
+#define NODE_EXEC 0x04
+
+extern struct node *node_find(const struct node *node, const char *path);
+extern struct node *node_create(struct node *parent, const char *name, enum node_type type);
+extern void *node_destroy(struct node *node);
+
+extern struct node * const node_next_sibling(const struct node *node);
+extern struct node * const node_prev_sibling(const struct node *node);
+
+extern struct node * const node_child(const struct node *node);
+extern struct node * const node_parent(const struct node *node);
+
+extern void node_set_mode(struct node *node, int mode);
+extern void node_set_data(struct node *node, void *data);
+
+extern const int const node_mode(const struct node *node);
+extern void * const node_data(const struct node *node);
+
+extern void node_set_type(struct node *node, enum node_type type);
+extern const enum node_type const node_type(const struct node *node);
+
+extern const char * const node_name(const struct node *node);
+
+extern char *node_to_abspath(const struct node *node);
+
+extern int node_age(struct node *node);
+extern void node_set_age(struct node *node, int age);
+
+extern void node_delete(struct node *node, void (del_cb)(struct node *node));
+/* End of a file */
diff --git a/util_liveinfo/src/liveinfo.c b/util_liveinfo/src/liveinfo.c
new file mode 100644
index 0000000..058d696
--- /dev/null
+++ b/util_liveinfo/src/liveinfo.c
@@ -0,0 +1,1795 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.tizenopensource.org/license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <libgen.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/shm.h>
+#include <sys/ipc.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/Xfixes.h>
+#include <X11/extensions/XShm.h>
+#include <X11/Xutil.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <packet.h>
+#include <com-core_packet.h>
+#include <com-core.h>
+
+#include <livebox-service.h>
+
+#include <Ecore.h>
+
+#include "liveinfo.h"
+#include "node.h"
+
+#define PROMPT "liveinfo "
+
+struct package {
+ int primary;
+ char *pkgid;
+
+ int pid;
+ char *slavename;
+ char *abi;
+ int refcnt;
+ int fault_count;
+ int inst_count;
+};
+
+struct instance {
+ char *id;
+ char *cluster;
+ char *category;
+ double period;
+ char *state;
+ int width;
+ int height;
+};
+
+struct slave {
+ int pid;
+ char *pkgname;
+ char *abi;
+ int secured;
+ int refcnt;
+ int fault_count;
+ char *state;
+ int loaded_inst;
+ int loaded_pkg;
+ double ttl;
+};
+
+enum command {
+ NOP,
+ PKG_LIST,
+ INST_LIST,
+ SLAVE_LIST,
+ INST_CTRL,
+ SLAVE_CTRL,
+ MASTER_CTRL,
+};
+
+static struct info {
+ int fifo_handle;
+ int fd;
+ Ecore_Fd_Handler *fd_handler;
+ Ecore_Fd_Handler *in_handler;
+
+ struct node *rootdir;
+ struct node *curdir;
+ struct node *targetdir;
+
+ enum command cmd;
+
+ int input_fd;
+ int verbose;
+
+ int age;
+
+ char *history[1024];
+ int history_top;
+ int history_idx;
+
+ struct node *quick_search_node;
+ int quick_idx;
+} s_info = {
+ .fifo_handle = -EINVAL,
+ .fd = -EINVAL,
+ .fd_handler = NULL,
+ .in_handler = NULL,
+ .rootdir = NULL,
+ .curdir = NULL,
+ .targetdir = NULL,
+ .cmd = NOP,
+ .input_fd = STDIN_FILENO,
+ .verbose = 0,
+ .age = 0,
+ .history = { 0, },
+ .history_top = 0,
+ .history_idx = 0,
+ .quick_search_node = NULL,
+ .quick_idx = 0,
+};
+
+char *optarg;
+int errno;
+int optind;
+int optopt;
+int opterr;
+
+static Eina_Bool input_cb(void *data, Ecore_Fd_Handler *fd_handler);
+
+static Eina_Bool process_line_cb(void *data)
+{
+ input_cb(NULL, NULL);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static inline void prompt(const char *cmdline)
+{
+ char *path;
+
+ if (s_info.input_fd != STDIN_FILENO) {
+ /* To prevent recursive call, add function to the main loop (idler) */
+ ecore_idler_add(process_line_cb, NULL);
+ return;
+ }
+
+ path = node_to_abspath(s_info.curdir);
+ printf(PROMPT"%s # %s", path, cmdline ? cmdline : "");
+ free(path);
+}
+
+static void provider_del_cb(struct node *node)
+{
+ struct slave *info;
+
+ info = node_data(node);
+ if (!info)
+ return;
+
+ free(info->pkgname);
+ free(info->abi);
+ free(info->state);
+ free(info);
+}
+
+static void package_del_cb(struct node *node)
+{
+ struct package *info;
+
+ info = node_data(node);
+ if (!info)
+ return;
+
+ free(info->pkgid);
+ free(info->slavename);
+ free(info->abi);
+ free(info);
+}
+
+static void inst_del_cb(struct node *node)
+{
+ struct instance *info;
+
+ info = node_data(node);
+ if (!info)
+ return;
+
+ free(info->id);
+ free(info->cluster);
+ free(info->category);
+ free(info->state);
+ free(info);
+}
+
+static inline void ls(void)
+{
+ struct node *node;
+ int cnt = 0;
+ int is_package;
+ int is_provider;
+ int is_instance;
+ struct node *next_node;
+
+ if (!(node_mode(s_info.targetdir) & NODE_READ)) {
+ printf("Access denied\n");
+ return;
+ }
+
+ is_package = node_name(s_info.targetdir) && !strcmp(node_name(s_info.targetdir), "package");
+ is_provider = !is_package && node_name(s_info.targetdir) && !strcmp(node_name(s_info.targetdir), "provider");
+ is_instance = !is_package && !is_provider && node_parent(s_info.targetdir) && node_name(node_parent(s_info.targetdir)) && !strcmp(node_name(node_parent(s_info.targetdir)), "package");
+
+ node = node_child(s_info.targetdir);
+ while (node) {
+ if (is_package) {
+ struct package *info;
+
+ next_node = node_next_sibling(node);
+ if (node_age(node) != s_info.age) {
+ node_delete(node, package_del_cb);
+ node = next_node;
+ continue;
+ }
+
+ info = node_data(node);
+ printf(" %3d %20s %5s ", info->inst_count, info->slavename ? info->slavename : "(none)", info->abi ? info->abi : "?");
+ } else if (is_provider) {
+ struct slave *info;
+
+ next_node = node_next_sibling(node);
+ if (node_age(node) != s_info.age) {
+ node_delete(node, provider_del_cb);
+ node = next_node;
+ continue;
+ }
+
+ info = node_data(node);
+ printf("%6d %3d %5s %5.2f ", info->pid, info->loaded_inst, info->abi ? info->abi : "?", info->ttl);
+ } else if (is_instance) {
+ struct instance *info;
+ struct stat stat;
+ char buf[4096];
+
+ next_node = node_next_sibling(node);
+
+ if (node_age(node) != s_info.age) {
+ node_delete(node, inst_del_cb);
+ node = next_node;
+ continue;
+ }
+
+ info = node_data(node);
+
+ printf(" %5.2f %6s %10s %10s %4dx%-4d ", info->period, info->state, info->cluster, info->category, info->width, info->height);
+ snprintf(buf, sizeof(buf), "/opt/usr/share/live_magazine/reader/%s", node_name(node));
+ if (lstat(buf, &stat) < 0)
+ printf("%3d ERR ", errno);
+ else
+ printf("%2.2lf KB ", (double)stat.st_size / 1024.0f);
+ }
+
+ if (node_type(node) == NODE_DIR)
+ printf("%s/", node_name(node));
+ else if (node_type(node) == NODE_FILE)
+ printf("%s", node_name(node));
+
+ printf("\n");
+ node = node_next_sibling(node);
+ cnt++;
+ }
+
+ printf("Total: %d\n", cnt);
+}
+
+static void send_slave_list(void)
+{
+ struct packet *packet;
+
+ if (s_info.cmd != NOP) {
+ printf("Previous command is not finished\n");
+ return;
+ }
+
+ packet = packet_create_noack("slave_list", "d", 0.0f);
+ if (!packet) {
+ printf("Failed to create a packet\n");
+ return;
+ }
+
+ com_core_packet_send_only(s_info.fd, packet);
+ packet_destroy(packet);
+ s_info.cmd = SLAVE_LIST;
+ s_info.age++;
+}
+
+/*!
+ * var = debug, slave_max_load
+ * cmd = set / get
+ */
+static void send_command(const char *cmd, const char *var, const char *val)
+{
+ struct packet *packet;
+
+ if (s_info.cmd != NOP) {
+ printf("Previous command is not finished\n");
+ return;
+ }
+
+ packet = packet_create_noack("master_ctrl", "sss", cmd, var, val);
+ com_core_packet_send_only(s_info.fd, packet);
+ packet_destroy(packet);
+ s_info.cmd = MASTER_CTRL;
+ s_info.age++;
+}
+
+static int pkglist_cb(const char *appid, const char *lbid, int is_prime, void *data)
+{
+ struct node *parent = data;
+ struct node *node;
+ struct package *info;
+
+ node = node_find(parent, lbid);
+ if (node) {
+ info = node_data(node);
+ if (!info) {
+ printf("Invalid node\n");
+ return -EINVAL;
+ }
+
+ free(info->pkgid);
+ info->pkgid = strdup(appid);
+ if (!info->pkgid) {
+ printf("Error: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ node_set_age(node, s_info.age);
+ return 0;
+ }
+
+ info = calloc(1, sizeof(*info));
+ if (!info) {
+ printf("Error: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ info->pkgid = strdup(appid);
+ if (!info->pkgid) {
+ printf("Error: %s\n", strerror(errno));
+ free(info);
+ return -ENOMEM;
+ }
+
+ info->primary = is_prime;
+
+ node = node_create(parent, lbid, NODE_DIR);
+ if (!node) {
+ free(info->pkgid);
+ free(info);
+ return -ENOMEM;
+ }
+
+ node_set_mode(node, NODE_READ | NODE_EXEC);
+ node_set_data(node, info);
+ node_set_age(node, s_info.age);
+ return 0;
+}
+
+static void send_pkg_list(void)
+{
+ struct packet *packet;
+
+ if (s_info.cmd != NOP) {
+ printf("Previous command is not finished\n");
+ return;
+ }
+
+ packet = packet_create_noack("pkg_list", "d", 0.0f);
+ if (!packet) {
+ printf("Failed to create a packet\n");
+ return;
+ }
+
+ com_core_packet_send_only(s_info.fd, packet);
+ packet_destroy(packet);
+ s_info.cmd = PKG_LIST;
+ s_info.age++;
+
+ livebox_service_get_pkglist(pkglist_cb, s_info.targetdir);
+}
+
+static void send_inst_delete(void)
+{
+ struct packet *packet;
+ struct node *parent;
+ const char *name;
+ struct instance *inst;
+
+ if (s_info.cmd != NOP) {
+ printf("Previous command is not finished\n");
+ return;
+ }
+
+ parent = node_parent(s_info.targetdir);
+ if (!parent) {
+ printf("Invalid argument\n");
+ return;
+ }
+
+ if (!node_parent(parent)) {
+ printf("Invalid argument\n");
+ return;
+ }
+
+ name = node_name(node_parent(parent));
+ if (!name || strcmp(name, "package")) {
+ printf("Invalid argument\n");
+ return;
+ }
+
+ inst = node_data(s_info.targetdir);
+ name = node_name(parent);
+
+ packet = packet_create_noack("pkg_ctrl", "sss", "rminst", name, inst->id);
+ if (!packet) {
+ printf("Failed to create a packet\n");
+ return;
+ }
+
+ com_core_packet_send_only(s_info.fd, packet);
+ packet_destroy(packet);
+ s_info.cmd = INST_CTRL;
+ s_info.age++;
+}
+
+static void send_inst_list(const char *pkgname)
+{
+ struct packet *packet;
+
+ if (s_info.cmd != NOP) {
+ printf("Previous command is not finished\n");
+ return;
+ }
+
+ packet = packet_create_noack("inst_list", "s", pkgname);
+ if (!packet) {
+ printf("Failed to create a packet\n");
+ return;
+ }
+
+ com_core_packet_send_only(s_info.fd, packet);
+ packet_destroy(packet);
+ s_info.cmd = INST_LIST;
+ s_info.age++;
+}
+
+static inline void help(void)
+{
+ printf("liveinfo - Livebox utility\n");
+ printf("------------------------------ [Option] ------------------------------\n");
+ printf("-b Batch mode\n");
+ printf("------------------------------ [Command list] ------------------------------\n");
+ printf("cd [PATH] - Change directory\n");
+ printf("ls [ | PATH] - List up content as a file\n");
+ printf("rm [PKG_ID|INST_ID] - Delete package or instance\n");
+ printf("stat [path] - Display the information of given path\n");
+ printf("set [debug] [on|off] Set the control variable of master provider\n");
+ printf("x damage Pix x y w h - Create damage event for given pixmap\n");
+ printf("x move Pix x y - Move the window\n");
+ printf("x resize Pix w h - Resize the window\n");
+ printf("x map Pix - Show the window\n");
+ printf("x unmap Pix - Hide the window\n");
+ printf("sh [command] Execute shell command, [command] should be abspath\n");
+ printf("exit - \n");
+ printf("quit - \n");
+ printf("----------------------------------------------------------------------------\n");
+}
+
+static inline void init_directory(void)
+{
+ struct node *node;
+ s_info.rootdir = node_create(NULL, NULL, NODE_DIR);
+ if (!s_info.rootdir)
+ return;
+ node_set_mode(s_info.rootdir, NODE_READ | NODE_EXEC);
+
+ node = node_create(s_info.rootdir, "provider", NODE_DIR);
+ if (!node) {
+ node_destroy(s_info.rootdir);
+ s_info.rootdir = NULL;
+ return;
+ }
+ node_set_mode(node, NODE_READ | NODE_EXEC);
+
+ node = node_create(s_info.rootdir, "package", NODE_DIR);
+ if (!node) {
+ node_destroy(node_child(s_info.rootdir));
+ node_destroy(s_info.rootdir);
+ s_info.rootdir = NULL;
+ return;
+ }
+ node_set_mode(node, NODE_READ | NODE_EXEC);
+
+ s_info.curdir = s_info.rootdir;
+ return;
+}
+
+static inline void fini_directory(void)
+{
+}
+
+static inline struct node *update_target_dir(const char *cmd)
+{
+ struct node *node;
+
+ node = (*cmd == '/') ? s_info.rootdir : s_info.curdir;
+ node = node_find(node, cmd);
+
+ return node;
+}
+
+static int get_token(const char *src, char *out)
+{
+ int len = 0;
+ while (*src && *src == ' ') src++;
+
+ if (!*src)
+ return 0;
+
+ while (*src && *src != ' ') {
+ *out++ = *src++;
+ len++;
+ }
+
+ *out = '\0';
+ return len;
+}
+
+static inline int do_stat(const char *cmd)
+{
+ int i;
+ struct node *node;
+ struct node *parent;
+ char *tmp;
+ enum stat_type {
+ PKG_INSTANCE = 0x01,
+ PKG,
+ PROVIDER_INSTANCE,
+ PROVIDER,
+ ROOT,
+ } type;
+
+ cmd += 5;
+ while (*cmd && *cmd == ' ') cmd++;
+
+ if (!*cmd){
+ printf("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ node = node_find(*cmd == '/' ? s_info.rootdir : s_info.curdir, cmd);
+ if (!node) {
+ printf("Invalid path\n");
+ return -EINVAL;
+ }
+
+ i = 0;
+ type = ROOT;
+ parent = node_parent(node);
+ while (parent) {
+ if (!node_name(parent)) {
+ printf("%s has no info\n", node_name(node));
+ return -EINVAL;
+ } else if (!strcmp(node_name(parent), "package")) {
+ type = (i == 0) ? PKG : PKG_INSTANCE;
+ break;
+ } else if (!strcmp(node_name(parent), "provider")){
+ type = (i == 0) ? PROVIDER : PROVIDER_INSTANCE;
+ break;
+ }
+
+ parent = node_parent(parent);
+ i++;
+ if (i > 1) {
+ printf("%s is invalid path\n", node_name(node));
+ return -EINVAL;
+ }
+ }
+
+ switch (type){
+ case PKG:
+ tmp = livebox_service_i18n_name(node_name(node), NULL);
+ printf("Name: %s (", tmp);
+ free(tmp);
+
+ i = livebox_service_is_enabled(node_name(node));
+ printf("%s)\n", i ? "enabled" : "disabled");
+
+ tmp = livebox_service_i18n_icon(node_name(node), NULL);
+ printf("Icon: %s\n", tmp);
+ free(tmp);
+
+ tmp = livebox_service_provider_name(node_name(node));
+ printf("Provider: %s (content:", tmp);
+ free(tmp);
+
+ tmp = livebox_service_content(node_name(node));
+ printf("%s)\n", tmp);
+ free(tmp);
+
+ tmp = livebox_service_lb_script_path(node_name(node));
+ printf("LB Script: %s (", tmp);
+ free(tmp);
+
+ tmp = livebox_service_lb_script_group(node_name(node));
+ printf("%s)\n", tmp);
+ free(tmp);
+
+ tmp = livebox_service_pd_script_path(node_name(node));
+ printf("PD Script: %s (", tmp);
+ free(tmp);
+
+ tmp = livebox_service_pd_script_group(node_name(node));
+ printf("%s)\n", tmp);
+ free(tmp);
+
+ i = livebox_service_mouse_event(node_name(node));
+ printf("Mouse event: %s\n", i ? "enabled" : "disabled");
+
+ i = livebox_service_touch_effect(node_name(node));
+ printf("Touch effect: %s\n", i ? "enabled" : "disabled");
+ break;
+ case PROVIDER:
+ printf("Not supported yet\n");
+ break;
+ case PKG_INSTANCE:
+ printf("Not supported yet\n");
+ break;
+ case PROVIDER_INSTANCE:
+ printf("Not supported yet\n");
+ break;
+ case ROOT:
+ printf("Not supported yet\n");
+ break;
+ }
+
+ return 0;
+}
+
+static inline int do_set(const char *cmd)
+{
+ int i;
+ char variable[4096] = { '0', };
+
+ cmd += 4;
+ i = get_token(cmd, variable);
+
+ cmd += i;
+ while (*cmd && *cmd == ' ') cmd++;
+
+ if (!i || !*cmd) {
+ printf("Invalid argument(%s): set [VAR] [VAL]\n", cmd);
+ return -EINVAL;
+ }
+
+ send_command("set", variable, cmd);
+ return 0;
+}
+
+static inline int do_get(const char *cmd)
+{
+ cmd += 4;
+
+ while (*cmd && *cmd == ' ') cmd++;
+ if (!*cmd) {
+ printf("Invalid argument(%s): get [VAR]\n", cmd);
+ return -EINVAL;
+ }
+
+ send_command("get", cmd, "");
+ return 0;
+}
+
+static inline int do_ls(const char *cmd)
+{
+ const char *name;
+ struct node *parent;
+
+ cmd += 2;
+
+ while (*cmd && *cmd == ' ')
+ cmd++;
+
+ s_info.targetdir = *cmd ? update_target_dir(cmd) : s_info.curdir;
+ if (!s_info.targetdir) {
+ printf("%s is not exists\n", cmd);
+ return -ENOENT;
+ }
+
+ name = node_name(s_info.targetdir);
+ if (name) {
+ if (!strcmp(name, "package")) {
+ if (s_info.cmd == NOP) {
+ send_pkg_list();
+ return 0;
+ }
+
+ printf("Waiting the server response\n");
+ return -EBUSY;
+ } else if (!strcmp(name, "provider")) {
+ if (s_info.cmd == NOP) {
+ send_slave_list();
+ return 0;
+ }
+
+ printf("Waiting the server response\n");
+ return -EBUSY;
+ }
+ }
+
+ parent = node_parent(s_info.targetdir);
+ if (parent && node_name(parent)) {
+ if (!strcmp(node_name(parent), "package")) {
+ if (s_info.cmd != NOP) {
+ printf("Waiting the server response\n");
+ return -EBUSY;
+ }
+
+ send_inst_list(name);
+ return 0;
+ }
+ }
+
+ ls();
+ return -1;
+}
+
+static inline int do_cd(const char *cmd)
+{
+ cmd += 2;
+
+ while (*cmd && *cmd == ' ')
+ cmd++;
+
+ if (!*cmd)
+ return -1;
+
+ if (s_info.cmd != NOP) {
+ printf("Waiting the server response\n");
+ return -EBUSY;
+ }
+
+ s_info.targetdir = update_target_dir(cmd);
+ if (!s_info.targetdir) {
+ printf("%s is not exists\n", cmd);
+ return -ENOENT;
+ }
+
+ if (node_type(s_info.targetdir) != NODE_DIR) {
+ printf("Unable change directory to %s\n", cmd);
+ return -EINVAL;
+ }
+
+ if (!(node_mode(s_info.targetdir) & NODE_EXEC)) {
+ printf("Access denied %s\n", cmd);
+ return -EACCES;
+ }
+
+ s_info.curdir = s_info.targetdir;
+ return -1;
+}
+
+static inline int do_rm(const char *cmd)
+{
+ cmd += 2;
+ while (*cmd && *cmd == ' ') cmd++;
+ if (!*cmd)
+ return -1;
+
+ if (s_info.cmd != NOP) {
+ printf("Waiting the server response\n");
+ return -EBUSY;
+ }
+
+ s_info.targetdir = update_target_dir(cmd);
+ if (!s_info.targetdir) {
+ printf("%s is not exists\n", cmd);
+ return -ENOENT;
+ }
+
+ if (!(node_mode(s_info.targetdir) & NODE_WRITE)) {
+ printf("Access denied %s\n", cmd);
+ return -EACCES;
+ }
+
+ send_inst_delete();
+ return 0;
+}
+
+#if !defined(WCOREDUMP)
+#define WCOREDUMP(a) 0
+#endif
+
+static inline void do_sh(const char *cmd)
+{
+ pid_t pid;
+
+ cmd += 3;
+
+ while (*cmd && *cmd == ' ') cmd++;
+ if (!*cmd)
+ return;
+
+ pid = fork();
+ if (pid == 0) {
+ char command[256];
+ int idx;
+ idx = 0;
+
+ while (idx < (sizeof(command) - 1) && *cmd && *cmd != ' ')
+ command[idx++] = *cmd++;
+ command[idx] = '\0';
+
+ if (execl(command, cmd, NULL) < 0)
+ printf("Failed to execute: %s\n", strerror(errno));
+
+ exit(0);
+ } else if (pid < 0) {
+ printf("Failed to create a new process: %s\n", strerror(errno));
+ } else {
+ int status;
+ if (waitpid(pid, &status, 0) < 0) {
+ printf("error: %s\n", strerror(errno));
+ } else {
+ if (WIFEXITED(status)) {
+ printf("Exit: %d\n", WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ printf("Terminated by %d %s\n", WTERMSIG(status), WCOREDUMP(status) ? " - core generated" : "");
+ } else if (WIFSTOPPED(status)) {
+ printf("Stopped by %d\n", WSTOPSIG(status));
+ } else if (WIFCONTINUED(status)) {
+ printf("Child is resumed\n");
+ }
+ }
+ }
+}
+
+static inline int get_pixmap_size(Display *disp, Pixmap id, int *x, int *y, unsigned int *w, unsigned int *h)
+{
+ Window dummy_win;
+ unsigned int dummy_border, dummy_depth;
+ int _x;
+ int _y;
+
+ if (!x)
+ x = &_x;
+ if (!y)
+ y = &_y;
+
+ if (!XGetGeometry(disp, id, &dummy_win, x, y, w, h, &dummy_border, &dummy_depth))
+ return -EFAULT;
+
+ return 0;
+}
+
+static inline int do_capture(Display *disp, Pixmap id, const char *filename)
+{
+ XShmSegmentInfo si;
+ XImage *xim;
+ Visual *visual;
+ unsigned int w;
+ unsigned int h;
+ int bufsz;
+ int fd;
+ Screen *screen;
+
+ screen = DefaultScreenOfDisplay(disp);
+ visual = DefaultVisualOfScreen(screen);
+
+ if (get_pixmap_size(disp, id, NULL, NULL, &w, &h) < 0) {
+ printf("Failed to get size of a pixmap\n");
+ return -EINVAL;
+ }
+
+ printf("Pixmap size: %dx%d\n", w, h);
+ bufsz = w * h * sizeof(int);
+
+ si.shmid = shmget(IPC_PRIVATE, bufsz, IPC_CREAT | 0666);
+ if (si.shmid < 0) {
+ printf("shmget: %s\n", strerror(errno));
+ return -EFAULT;
+ }
+
+ si.readOnly = False;
+ si.shmaddr = shmat(si.shmid, NULL, 0);
+ if (si.shmaddr == (void *)-1) {
+
+ if (shmctl(si.shmid, IPC_RMID, 0) < 0)
+ printf("shmctl: %s\n", strerror(errno));
+
+ return -EFAULT;
+ }
+
+ /*!
+ * \NOTE
+ * Use the 24 bits Pixmap for Video player
+ */
+ xim = XShmCreateImage(disp, visual, 24 /* (depth << 3) */, ZPixmap, NULL, &si, w, h);
+ if (xim == NULL) {
+ if (shmdt(si.shmaddr) < 0)
+ printf("shmdt: %s\n", strerror(errno));
+
+ if (shmctl(si.shmid, IPC_RMID, 0) < 0)
+ printf("shmctl: %s\n", strerror(errno));
+
+ return -EFAULT;
+ }
+
+ xim->data = si.shmaddr;
+ XShmAttach(disp, &si);
+
+ XShmGetImage(disp, id, xim, 0, 0, 0xFFFFFFFF);
+ XSync(disp, False);
+
+ fd = open(filename, O_CREAT | O_RDWR, 0644);
+ if (fd >= 0) {
+ if (write(fd, xim->data, bufsz) != bufsz)
+ printf("Data is not fully written\n");
+
+ close(fd);
+ } else {
+ printf("Error: %sn\n", strerror(errno));
+ }
+
+ XShmDetach(disp, &si);
+ XDestroyImage(xim);
+
+ if (shmdt(si.shmaddr) < 0)
+ printf("shmdt: %s\n", strerror(errno));
+
+ if (shmctl(si.shmid, IPC_RMID, 0) < 0)
+ printf("shmctl: %s\n", strerror(errno));
+
+ return 0;
+}
+
+static inline void do_x(const char *cmd)
+{
+ Display *disp;
+
+ cmd += 2;
+
+ while (*cmd && *cmd == ' ') cmd++;
+ if (!*cmd)
+ return;
+
+ disp = XOpenDisplay(NULL);
+ if (!disp) {
+ printf("Failed to connect to the X\n");
+ return;
+ }
+
+ if (!strncasecmp(cmd, "damage ", 7)) {
+ unsigned int winId;
+ XRectangle rect;
+ XserverRegion region;
+ int x, y, w, h;
+
+ cmd += 7;
+
+ if (sscanf(cmd, "%u %d %d %d %d", &winId, &x, &y, &w, &h) != 5) {
+ printf("Invalid argument\nx damage WINID_DEC X Y W H\n");
+ return;
+ }
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ region = XFixesCreateRegion(disp, &rect, 1);
+ XDamageAdd(disp, winId, region);
+ XFixesDestroyRegion(disp, region);
+ XFlush(disp);
+
+ printf("Damage: %u %d %d %d %d\n", winId, x, y, w, h);
+ } else if (!strncasecmp(cmd, "capture ", 8)) {
+ unsigned int winId;
+ char filename[256];
+
+ cmd += 8;
+
+ if (sscanf(cmd, "%u %255[^ ]", &winId, filename) != 2) {
+ printf("Invalid argument\nx capture WINID_DEC FILENAME (%s)\n", cmd);
+ return;
+ }
+ if (do_capture(disp, winId, filename) == 0)
+ printf("Captured: %s\n", filename);
+ } else if (!strncasecmp(cmd, "resize ", 7)) {
+ unsigned int winId;
+ int w;
+ int h;
+
+ cmd += 7;
+
+ if (sscanf(cmd, "%u %d %d", &winId, &w, &h) != 3) {
+ printf("Invalid argument\nx resize WINID_DEC W H\n");
+ return;
+ }
+
+ XResizeWindow(disp, winId, w, h);
+ printf("Resize: %u %d %d\n", winId, w, h);
+ } else if (!strncasecmp(cmd, "move ", 5)) {
+ unsigned int winId;
+ int x;
+ int y;
+
+ cmd += 5;
+ if (sscanf(cmd, "%u %d %d", &winId, &x, &y) != 3) {
+ printf("Invalid argument\nx move WINID_DEC X Y\n");
+ return;
+ }
+
+ XMoveWindow(disp, winId, x, y);
+ printf("Move: %u %d %d\n", winId, x, y);
+ } else if (!strncasecmp(cmd, "map ", 4)) {
+ unsigned int winId;
+ cmd += 4;
+ if (sscanf(cmd, "%u", &winId) != 1) {
+ printf("Invalid argument\nx map WINID_DEC\n");
+ return;
+ }
+ XMapRaised(disp, winId);
+ printf("Map: %u\n", winId);
+ } else if (!strncasecmp(cmd, "unmap ", 6)) {
+ unsigned int winId;
+ cmd += 6;
+ if (sscanf(cmd, "%u", &winId) != 1) {
+ printf("Invalid argument\nx unmap WINID_DEC\n");
+ return;
+ }
+ XUnmapWindow(disp, winId);
+ printf("Unmap: %u\n", winId);
+ } else {
+ printf("Unknown command\n");
+ }
+
+ XCloseDisplay(disp);
+}
+
+static inline void put_command(const char *cmd)
+{
+ if (s_info.history[s_info.history_top]) {
+ free(s_info.history[s_info.history_top]);
+ s_info.history[s_info.history_top] = NULL;
+ }
+
+ s_info.history[s_info.history_top] = strdup(cmd);
+ s_info.history_top = (s_info.history_top + !!s_info.history[s_info.history_top]) % (sizeof(s_info.history) / sizeof(s_info.history[0]));
+}
+
+static inline const char *get_command(int idx)
+{
+ idx = s_info.history_top + idx;
+ while (idx < 0)
+ idx += (sizeof(s_info.history) / sizeof(s_info.history[0]));
+
+ return s_info.history[idx];
+}
+
+static inline void do_command(const char *cmd)
+{
+ /* Skip the first spaces */
+ while (*cmd && *cmd == ' ') cmd++;
+
+ if (strlen(cmd) && *cmd != '#') {
+ if (!strncasecmp(cmd, "exit", 4) || !strncasecmp(cmd, "quit", 4)) {
+ ecore_main_loop_quit();
+ } else if (!strncasecmp(cmd, "set ", 4)) {
+ if (do_set(cmd) == 0)
+ return;
+ } else if (!strncasecmp(cmd, "stat ", 5)) {
+ do_stat(cmd);
+ } else if (!strncasecmp(cmd, "get ", 4)) {
+ if (do_get(cmd) == 0)
+ return;
+ } else if (!strncasecmp(cmd, "ls", 2)) {
+ if (do_ls(cmd) == 0)
+ return;
+ } else if (!strncasecmp(cmd, "cd", 2)) {
+ if (do_cd(cmd) == 0)
+ return;
+ } else if (!strncasecmp(cmd, "rm", 2)) {
+ if (do_rm(cmd) == 0)
+ return;
+ } else if (!strncasecmp(cmd, "sh ", 3)) {
+ do_sh(cmd);
+ } else if (!strncasecmp(cmd, "x ", 2)) {
+ do_x(cmd);
+ } else {
+ help();
+ }
+ }
+
+ prompt(NULL);
+ return;
+}
+
+static Eina_Bool input_cb(void *data, Ecore_Fd_Handler *fd_handler)
+{
+ static int idx = 0;
+ static char cmd_buffer[256];
+ char ch;
+ int fd;
+ int ret;
+ const char escape_str[] = { 0x1b, 0x5b, 0x0 };
+ const char *escape_ptr = escape_str;
+ const char *tmp;
+
+ if (fd_handler) {
+ fd = ecore_main_fd_handler_fd_get(fd_handler);
+ if (fd < 0) {
+ printf("FD is not valid: %d\n", fd);
+ return ECORE_CALLBACK_CANCEL;
+ }
+ } else {
+ fd = s_info.input_fd;
+ }
+
+ /*!
+ * \note
+ * Using this routine, we can implement the command recommend algorithm.
+ * When a few more characters are matched with history of command, we can show it to user
+ * Then the user will choose one or write new command
+ */
+
+ /* Silly.. Silly */
+ while ((ret = read(fd, &ch, sizeof(ch))) == sizeof(ch)) {
+ if (*escape_ptr == '\0') {
+ /* Function key */
+ switch (ch) {
+ case 0x41: /* UP */
+ printf("%s2K%s1G", escape_str, escape_str);
+ tmp = get_command(--s_info.history_idx);
+ if (!tmp) {
+ s_info.history_idx = 0;
+ cmd_buffer[0] = '\0';
+ prompt(NULL);
+ } else {
+ strcpy(cmd_buffer, tmp);
+ idx = strlen(cmd_buffer);
+ prompt(cmd_buffer);
+ }
+ break;
+ case 0x42: /* DOWN */
+ if (s_info.history_idx >= 0)
+ break;
+
+ printf("%s2K%s1G", escape_str, escape_str);
+ tmp = get_command(++s_info.history_idx);
+ if (s_info.history_idx == 0) {
+ s_info.history_idx = 0;
+ cmd_buffer[0] = '\0';
+ prompt(NULL);
+ } else {
+ strcpy(cmd_buffer, tmp);
+ idx = strlen(cmd_buffer);
+ prompt(cmd_buffer);
+ }
+ break;
+ case 0x43: /* RIGHT */
+ break;
+ case 0x44: /* LEFT */
+ break;
+ default:
+ break;
+ }
+
+ escape_ptr = escape_str;
+ continue;
+ } else if (ch == *escape_ptr) {
+ escape_ptr++;
+ continue;
+ }
+
+ switch (ch) {
+ case 0x08: /* BKSP */
+ cmd_buffer[idx] = '\0';
+ if (idx > 0) {
+ idx--;
+ cmd_buffer[idx] = ' ';
+ putc('\r', stdout);
+ prompt(cmd_buffer);
+ }
+
+ cmd_buffer[idx] = '\0';
+ putc('\r', stdout);
+ prompt(cmd_buffer);
+ break;
+ case 0x09: /* TAB */
+ if (!s_info.quick_search_node) {
+ s_info.quick_search_node = node_child(s_info.curdir);
+ s_info.quick_idx = idx;
+ } else {
+ s_info.quick_search_node = node_next_sibling(s_info.quick_search_node);
+ idx = s_info.quick_idx;
+ }
+
+ if (!s_info.quick_search_node)
+ break;
+
+ printf("%s2K%s1G", escape_str, escape_str);
+ strcpy(cmd_buffer + idx, node_name(s_info.quick_search_node));
+ idx += strlen(node_name(s_info.quick_search_node));
+ prompt(cmd_buffer);
+ break;
+ case '\n':
+ case '\r':
+ cmd_buffer[idx] = '\0';
+ idx = 0;
+ if (s_info.input_fd == STDIN_FILENO || s_info.verbose)
+ putc((int)'\n', stdout);
+ do_command(cmd_buffer);
+ put_command(cmd_buffer);
+ memset(cmd_buffer, 0, sizeof(cmd_buffer));
+ s_info.history_idx = 0;
+ s_info.quick_search_node = NULL;
+
+ /* Make a main loop processing for command handling */
+ return ECORE_CALLBACK_RENEW;
+ default:
+ cmd_buffer[idx++] = ch;
+
+ if (s_info.input_fd == STDIN_FILENO || s_info.verbose)
+ putc((int)ch, stdout);
+
+ if (idx == sizeof(cmd_buffer) - 1) {
+ cmd_buffer[idx] = '\0';
+ printf("\nCommand buffer is overflow: %s\n", cmd_buffer);
+ idx = 0;
+ }
+ break;
+ }
+ }
+
+ if (ret < 0 && !fd_handler)
+ ecore_main_loop_quit();
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void processing_line_buffer(const char *buffer)
+{
+ int pid;
+ char slavename[256];
+ char pkgname[256];
+ char abi[256];
+ char inst_id[4096];
+ char cluster[256];
+ char category[256];
+ char state[10];
+ int refcnt;
+ int fault_count;
+ int list_count;
+ int loaded_inst;
+ int loaded_pkg;
+ double ttl;
+ int secured;
+ double period;
+ int width;
+ int height;
+ struct node *node;
+ struct package *pkginfo;
+ struct instance *instinfo;
+ struct slave *slaveinfo;
+ int i;
+
+ switch (s_info.cmd) {
+ case PKG_LIST:
+ if (sscanf(buffer, "%d %255[^ ] %255[^ ] %255[^ ] %d %d %d", &pid, slavename, pkgname, abi, &refcnt, &fault_count, &list_count) != 7) {
+ printf("Invalid format : [%s]\n", buffer);
+ return;
+ }
+
+ node = node_find(s_info.targetdir, pkgname);
+ if (!node) {
+ pkginfo = calloc(1, sizeof(*pkginfo));
+ if (!pkginfo) {
+ printf("Error: %s\n", strerror(errno));
+ return;
+ }
+
+ pkginfo->pkgid = strdup("conf.file");
+ if (!pkginfo->pkgid)
+ printf("Error: %s\n", strerror(errno));
+
+ pkginfo->primary = 1;
+
+ node = node_create(s_info.targetdir, pkgname, NODE_DIR);
+ if (!node) {
+ free(pkginfo->pkgid);
+ free(pkginfo);
+ printf("Failed to create a new node (%s)\n", pkgname);
+ return;
+ }
+
+ node_set_mode(node, NODE_READ | NODE_EXEC);
+ node_set_data(node, pkginfo);
+ } else {
+ pkginfo = node_data(node);
+ if (!pkginfo) {
+ printf("Package info is inavlid\n");
+ return;
+ }
+
+ free(pkginfo->slavename);
+ free(pkginfo->abi);
+
+ pkginfo->slavename = NULL;
+ pkginfo->abi = NULL;
+ }
+
+ node_set_age(node, s_info.age);
+
+ pkginfo->slavename = strdup(slavename);
+ if (!pkginfo->slavename)
+ printf("Error: %s\n", strerror(errno));
+
+ pkginfo->abi = strdup(abi);
+ if (!pkginfo->abi)
+ printf("Error: %s\n", strerror(errno));
+
+ pkginfo->pid = pid;
+ pkginfo->refcnt = refcnt;
+ pkginfo->fault_count = fault_count;
+ pkginfo->inst_count = list_count;
+ break;
+ case SLAVE_LIST:
+ if (sscanf(buffer, "%d %[^ ] %[^ ] %[^ ] %d %d %d %[^ ] %d %d %lf", &pid, slavename, pkgname, abi, &secured, &refcnt, &fault_count, state, &loaded_inst, &loaded_pkg, &ttl) != 11) {
+ printf("Invalid format : [%s]\n", buffer);
+ return;
+ }
+ node = node_find(s_info.targetdir, slavename);
+ if (!node) {
+ slaveinfo = calloc(1, sizeof(*slaveinfo));
+ if (!slaveinfo) {
+ printf("Error: %s\n", strerror(errno));
+ return;
+ }
+
+ node = node_create(s_info.targetdir, slavename, NODE_DIR);
+ if (!node) {
+ free(slaveinfo);
+ return;
+ }
+
+ node_set_mode(node, NODE_READ | NODE_EXEC);
+ node_set_data(node, slaveinfo);
+ } else {
+ slaveinfo = node_data(node);
+ }
+
+ node_set_age(node, s_info.age);
+
+ free(slaveinfo->pkgname);
+ free(slaveinfo->abi);
+ free(slaveinfo->state);
+
+ slaveinfo->pkgname = strdup(pkgname);
+ if (!slaveinfo->pkgname)
+ printf("Error: %s\n", strerror(errno));
+
+ slaveinfo->abi = strdup(abi);
+ if (!slaveinfo->abi)
+ printf("Error: %s\n", strerror(errno));
+
+ slaveinfo->state = strdup(state);
+ if (!slaveinfo->state)
+ printf("Error: %s\n", strerror(errno));
+
+ slaveinfo->pid = pid;
+ slaveinfo->secured = secured;
+ slaveinfo->refcnt = refcnt;
+ slaveinfo->fault_count = fault_count;
+ slaveinfo->loaded_inst = loaded_inst;
+ slaveinfo->loaded_pkg = loaded_pkg;
+ slaveinfo->ttl = ttl;
+ break;
+ case INST_LIST:
+ if (sscanf(buffer, "%[^ ] %[^ ] %[^ ] %lf %[^ ] %d %d", inst_id, cluster, category, &period, state, &width, &height) != 7) {
+ printf("Invalid format : [%s]\n", buffer);
+ return;
+ }
+
+ for (i = strlen(inst_id); i > 0 && inst_id[i] != '/'; i--);
+ i += (inst_id[i] == '/');
+
+ node = node_find(s_info.targetdir, inst_id + i);
+ if (!node) {
+ instinfo = calloc(1, sizeof(*instinfo));
+ if (!instinfo) {
+ printf("Error: %s\n", strerror(errno));
+ return;
+ }
+
+ node = node_create(s_info.targetdir, inst_id + i, NODE_FILE);
+ if (!node) {
+ free(instinfo);
+ return;
+ }
+
+ node_set_mode(node, NODE_READ | NODE_WRITE);
+ node_set_data(node, instinfo);
+ } else {
+ instinfo = node_data(node);
+ }
+
+ node_set_age(node, s_info.age);
+
+ free(instinfo->id);
+ free(instinfo->cluster);
+ free(instinfo->category);
+ free(instinfo->state);
+
+ instinfo->id = strdup(inst_id);
+ if (!instinfo->id)
+ printf("Error: %s\n", strerror(errno));
+
+ instinfo->cluster = strdup(cluster);
+ if (!instinfo->cluster)
+ printf("Error: %s\n", strerror(errno));
+
+ instinfo->category = strdup(category);
+ if (!instinfo->category)
+ printf("Error: %s\n", strerror(errno));
+
+ instinfo->state = strdup(state);
+ if (!instinfo->state)
+ printf("Error: %s\n", strerror(errno));
+
+ instinfo->period = period;
+ instinfo->width = width;
+ instinfo->height = height;
+ break;
+ case INST_CTRL:
+ sscanf(buffer, "%d", &i);
+ printf("%s\n", strerror(i));
+ printf("Result: %d\n", i);
+ break;
+ case SLAVE_CTRL:
+ sscanf(buffer, "%d", &i);
+ printf("Result: %d\n", i);
+ break;
+ case MASTER_CTRL:
+ sscanf(buffer, "%d", &i);
+ printf("Result: %d\n", i);
+ break;
+ default:
+ break;
+ }
+}
+
+static inline void do_line_command(void)
+{
+ switch (s_info.cmd) {
+ case PKG_LIST:
+ ls();
+ break;
+ case INST_LIST:
+ ls();
+ break;
+ case SLAVE_LIST:
+ ls();
+ break;
+ case INST_CTRL:
+ break;
+ case SLAVE_CTRL:
+ break;
+ case MASTER_CTRL:
+ break;
+ default:
+ break;
+ }
+ prompt(NULL);
+}
+
+static Eina_Bool read_cb(void *data, Ecore_Fd_Handler *fd_handler)
+{
+ int fd;
+ static char *line_buffer = NULL;
+ static int line_index = 0;
+ static int bufsz = 256;
+ char ch;
+
+ fd = ecore_main_fd_handler_fd_get(fd_handler);
+ if (fd < 0) {
+ printf("FD is not valid: %d\n", fd);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ if (read(fd, &ch, sizeof(ch)) != sizeof(ch)) {
+ printf("Error: %s\n", strerror(errno));
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ if (!line_buffer) {
+ line_index = 0;
+ line_buffer = malloc(bufsz);
+ if (!line_buffer) {
+ printf("Error: %s\n", strerror(errno));
+ return ECORE_CALLBACK_CANCEL;
+ }
+ }
+
+ if (ch == '\n') { /* End of a line */
+ if (line_index == bufsz - 1) {
+ char *new_buf;
+ new_buf = realloc(line_buffer, bufsz + 2);
+ if (!new_buf) {
+ printf("Error: %s\n", strerror(errno));
+ free(line_buffer);
+ line_buffer = NULL;
+ line_index = 0;
+ bufsz = 256;
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ line_buffer = new_buf;
+ }
+
+ line_buffer[line_index] = '\0';
+
+ if (!strcmp(line_buffer, "EOD")) {
+ do_line_command();
+ s_info.cmd = NOP;
+ } else {
+ processing_line_buffer(line_buffer);
+ }
+
+ free(line_buffer);
+ line_buffer = NULL;
+ line_index = 0;
+ bufsz = 256;
+ } else {
+ char *new_buf;
+
+ line_buffer[line_index++] = ch;
+ if (line_index == bufsz - 1) {
+ bufsz += 256;
+ new_buf = realloc(line_buffer, bufsz);
+ if (!new_buf) {
+ printf("Error: %s\n", strerror(errno));
+ free(line_buffer);
+ line_buffer = NULL;
+ line_index = 0;
+ bufsz = 256;
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ line_buffer = new_buf;
+ }
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static int ret_cb(pid_t pid, int handle, const struct packet *packet, void *data)
+{
+ const char *fifo_name;
+ int ret;
+
+ if (packet_get(packet, "si", &fifo_name, &ret) != 2) {
+ printf("Invalid packet\n");
+ return -EFAULT;
+ }
+
+ if (ret != 0) {
+ printf("Returns %d\n", ret);
+ return ret;
+ }
+
+ printf("FIFO: %s\n", fifo_name);
+
+ s_info.fifo_handle = open(fifo_name, O_RDONLY | O_NONBLOCK);
+ if (s_info.fifo_handle < 0) {
+ printf("Error: %s\n", strerror(errno));
+ s_info.fifo_handle = -EINVAL;
+ ecore_main_loop_quit();
+ return -EINVAL;
+ }
+
+ s_info.fd_handler = ecore_main_fd_handler_add(s_info.fifo_handle, ECORE_FD_READ, read_cb, NULL, NULL, NULL);
+ if (!s_info.fd_handler) {
+ printf("Failed to add a fd handler\n");
+ close(s_info.fifo_handle);
+ s_info.fifo_handle = -EINVAL;
+ ecore_main_loop_quit();
+ return -EFAULT;
+ }
+
+ prompt(NULL);
+
+ if (s_info.input_fd == STDIN_FILENO) {
+ if (fcntl(s_info.input_fd, F_SETFL, O_NONBLOCK) < 0)
+ printf("Error: %s\n", strerror(errno));
+
+ s_info.in_handler = ecore_main_fd_handler_add(s_info.input_fd, ECORE_FD_READ, input_cb, NULL, NULL, NULL);
+ if (!s_info.in_handler) {
+ printf("Failed to add a input handler\n");
+ ecore_main_loop_quit();
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+static int disconnected_cb(int handle, void *data)
+{
+ printf("Disconnected\n");
+ ecore_main_loop_quit();
+ return 0;
+}
+
+static int connected_cb(int handle, void *data)
+{
+ struct packet *packet;
+
+ printf("Connected\n");
+
+ packet = packet_create("liveinfo_hello", "d", 0.0f);
+ if (!packet) {
+ printf("Failed to build a packet for hello\n");
+ com_core_packet_client_fini(s_info.fd);
+ s_info.fd = -EINVAL;
+ return -EFAULT;
+ }
+
+ s_info.fd = handle;
+
+ if (com_core_packet_async_send(s_info.fd, packet, 0.0f, ret_cb, NULL) < 0) {
+ printf("Failed to send a packet hello\n");
+ packet_destroy(packet);
+ com_core_packet_client_fini(s_info.fd);
+ s_info.fd = -EINVAL;
+ return -EFAULT;
+ }
+
+ packet_destroy(packet);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct termios ttystate;
+ static struct method s_table[] = {
+ {
+ .cmd = NULL,
+ .handler = NULL,
+ },
+ };
+ static struct option long_options[] = {
+ { "batchmode", required_argument, 0, 'b' },
+ { "help", no_argument, 0, 'h' },
+ { "verbose", required_argument, 0, 'v' },
+ { 0, 0, 0, 0 }
+ };
+ int option_index;
+ int c;
+
+ do {
+ c = getopt_long(argc, argv, "b:hv:", long_options, &option_index);
+ switch (c) {
+ case 'b':
+ if (!optarg || !*optarg) {
+ printf("Invalid argument\n");
+ help();
+ return -EINVAL;
+ }
+
+ if (s_info.input_fd != STDIN_FILENO) {
+ /* Close the previously, opened file */
+ close(s_info.input_fd);
+ }
+
+ s_info.input_fd = open(optarg, O_RDONLY);
+ if (s_info.input_fd < 0) {
+ printf("Unable to access %s (%s)\n", optarg, strerror(errno));
+ return -EIO;
+ }
+ break;
+ case 'h':
+ help();
+ return 0;
+ case 'v':
+ if (!optarg || !*optarg) {
+ printf("Invalid argument\n");
+ help();
+ return -EINVAL;
+ }
+
+ s_info.verbose = !strcmp(optarg, "true");
+ break;
+ default:
+ break;
+ }
+ } while (c != -1);
+
+ ecore_init();
+ g_type_init();
+
+ com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
+ com_core_add_event_callback(CONNECTOR_CONNECTED, connected_cb, NULL);
+ livebox_service_init();
+
+ s_info.fd = com_core_packet_client_init(SOCKET_FILE, 0, s_table);
+ if (s_info.fd < 0) {
+ printf("Failed to make a connection\n");
+ return -EIO;
+ }
+
+ if (s_info.input_fd == STDIN_FILENO) {
+ printf("Type your command on below empty line\n");
+
+ if (tcgetattr(s_info.input_fd, &ttystate) < 0) {
+ printf("Error: %s\n", strerror(errno));
+ } else {
+ ttystate.c_lflag &= ~(ICANON | ECHO);
+ ttystate.c_cc[VMIN] = 1;
+
+ if (tcsetattr(s_info.input_fd, TCSANOW, &ttystate) < 0)
+ printf("Error: %s\n", strerror(errno));
+ }
+ } else {
+ printf("Batch mode enabled\n");
+ }
+
+ if (setvbuf(stdout, (char *)NULL, _IONBF, 0) != 0)
+ printf("Error: %s\n", strerror(errno));
+
+ init_directory();
+
+ ecore_main_loop_begin();
+
+ fini_directory();
+ livebox_service_fini();
+
+ if (s_info.fd > 0) {
+ com_core_packet_client_fini(s_info.fd);
+ s_info.fd = -EINVAL;
+ }
+
+ if (s_info.fd_handler) {
+ ecore_main_fd_handler_del(s_info.fd_handler);
+ s_info.fd_handler = NULL;
+ }
+
+ if (s_info.input_fd == STDIN_FILENO) {
+ ttystate.c_lflag |= ICANON | ECHO;
+ if (tcsetattr(s_info.input_fd, TCSANOW, &ttystate) < 0)
+ printf("Error: %s\n", strerror(errno));
+ } else {
+ close(s_info.input_fd);
+ }
+
+ if (s_info.fifo_handle > 0) {
+ close(s_info.fifo_handle);
+ s_info.fifo_handle = -EINVAL;
+ }
+
+ if (s_info.in_handler) {
+ ecore_main_fd_handler_del(s_info.in_handler);
+ s_info.in_handler = NULL;
+ }
+
+ ecore_shutdown();
+ putc((int)'\n', stdout);
+ return 0;
+}
+
+/* End of a file */
diff --git a/util_liveinfo/src/node.c b/util_liveinfo/src/node.c
new file mode 100644
index 0000000..d68f096
--- /dev/null
+++ b/util_liveinfo/src/node.c
@@ -0,0 +1,362 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "node.h"
+
+struct node {
+ char *name;
+ enum node_type type;
+
+ void *data;
+
+ struct node *parent;
+ unsigned char mode;
+ int age;
+
+ struct {
+ struct node *next;
+ struct node *prev;
+ } sibling;
+
+ struct node *child;
+};
+
+int errno; /* External symbol */
+
+char *node_to_abspath(const struct node *node)
+{
+ char *path;
+ char *ptr;
+ const struct node *tmp;
+ int len = 0;
+
+ tmp = node;
+ while (tmp && node_name(tmp)) {
+ len += strlen(node_name(tmp)) + 1; /* trail '/' */
+ tmp = node_parent(tmp);
+ }
+
+ path = malloc(len + 3); /* '/' and '\0' */
+ if (!path)
+ return NULL;
+
+ if (!len) {
+ path[0] = '/';
+ path[1] = '\0';
+ } else {
+ ptr = path + len + 1;
+ *ptr = '\0';
+ ptr--;
+ *ptr = '/';
+ tmp = node;
+ while (tmp && node_name(tmp)) {
+ ptr -= (strlen(node_name(tmp)) + 1);
+ *ptr = '/';
+ strncpy(ptr + 1, node_name(tmp), strlen(node_name(tmp)));
+ tmp = node_parent(tmp);
+ }
+ }
+
+ return path;
+}
+
+static inline int next_state(int from, char ch)
+{
+ switch ( ch )
+ {
+ case '\0':
+ case '/':
+ return 1;
+ case '.':
+ if ( from == 1 ) return 2;
+ if ( from == 2 ) return 3;
+ }
+
+ return 4;
+}
+
+static inline void abspath(const char* pBuffer, char* pRet)
+{
+ int idx=0;
+ int state = 1;
+ int from;
+ int src_idx = 0;
+ int src_len = strlen(pBuffer);
+ pRet[idx] = '/';
+ idx ++;
+
+ while (src_idx <= src_len) {
+ from = state;
+ state = next_state(from, pBuffer[src_idx]);
+
+ switch (from) {
+ case 1:
+ if ( state != 1 ) {
+ pRet[idx] = pBuffer[src_idx];
+ idx ++;
+ }
+ break;
+ case 2:
+ if ( state == 1 ) {
+ if ( idx > 1 ) idx --;
+ } else {
+ pRet[idx] = pBuffer[src_idx];
+ idx ++;
+ }
+ break;
+ case 3:
+ // Only can go to the 1 or 4
+ if ( state == 1 ) {
+ idx -= 2;
+ if ( idx < 1 ) idx = 1;
+
+ while ( idx > 1 && pRet[idx] != '/' ) idx --; /* Remove .. */
+ if ( idx > 1 && pRet[idx] == '/' ) idx --;
+ while ( idx > 1 && pRet[idx] != '/' ) idx --; /* Remove parent folder */
+ }
+ case 4:
+ pRet[idx] = pBuffer[src_idx];
+ idx ++;
+ break;
+ }
+
+ pRet[idx] = '\0';
+ src_idx ++;
+ }
+}
+
+struct node *node_find(const struct node *node, const char *path)
+{
+ int len = 0;
+ char *ptr;
+ char *buffer;
+
+ if (*path != '/') {
+ while (node->parent && path[0] == '.' && path[1] == '.') {
+ if (path[2] != '/' && path[2] != '\0')
+ break;
+
+ path += 2;
+ path += (path[2] == '/');
+ node = node->parent;
+ }
+ }
+
+ buffer = malloc(strlen(path) + 3); /* add 2 more bytes */
+ if (!buffer) {
+ printf("Error: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ abspath(path, buffer);
+
+ ptr = buffer;
+ do {
+ ptr += (*ptr == '/');
+ for (len = 0; ptr[len] && ptr[len] != '/'; len++);
+ if (!len)
+ break;
+
+ if (!strncmp("..", ptr, len)) {
+ ptr += len;
+ node = node->parent ? node->parent : node;
+ continue;
+ }
+
+ if (!strncmp(".", ptr, len)) {
+ ptr += len;
+ continue;
+ }
+
+ node = node->child;
+ if (!node)
+ break;
+
+ while (node) {
+ if (!strncmp(node->name, ptr, len) && node->name[len] == '\0') {
+ ptr += len;
+ break;
+ }
+
+ node = node->sibling.next;
+ }
+ } while (*ptr && node);
+
+ free(buffer);
+ return (struct node *)node;
+}
+
+struct node *node_create(struct node *parent, const char *name, enum node_type type)
+{
+ struct node *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ printf("Error: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ node->parent = parent;
+
+ if (name) {
+ node->name = strdup(name);
+ if (!node->name) {
+ printf("Error: %s\n", strerror(errno));
+ free(node);
+ return NULL;
+ }
+ } else {
+ node->name = NULL;
+ }
+
+ node->type = type;
+
+ node->sibling.next = NULL;
+ node->sibling.prev = NULL;
+
+ node->child = NULL;
+ node->data = NULL;
+
+ if (parent) {
+ if (parent->child) {
+ struct node *tmp;
+ tmp = parent->child;
+ while (tmp->sibling.next)
+ tmp = tmp->sibling.next;
+
+ tmp->sibling.next = node;
+ node->sibling.prev = tmp;
+ } else {
+ parent->child = node;
+ }
+ }
+ return node;
+}
+
+void *node_destroy(struct node *node)
+{
+ void *data;
+
+ data = node->data;
+ free(node->name);
+ free(node);
+
+ return data;
+}
+
+void node_delete(struct node *node, void (del_cb)(struct node *node))
+{
+ struct node *tmp;
+ struct node *next;
+ struct node *parent;
+
+ if (node->sibling.prev)
+ node->sibling.prev->sibling.next = node->sibling.next;
+
+ if (node->sibling.next)
+ node->sibling.next->sibling.prev = node->sibling.prev;
+
+ /* Isolate the node */
+ node->sibling.prev = NULL;
+ node->sibling.next = NULL;
+
+ if (node->parent) {
+ if (node->parent->child == node)
+ node->parent->child = NULL;
+
+ node->parent = NULL;
+ }
+
+ tmp = node;
+ while (tmp) {
+ /* Reach to the leaf node */
+ while (tmp->child) tmp = tmp->child;
+
+ parent = tmp->parent;
+ next = tmp->sibling.next;
+
+ if (parent && parent->child == tmp)
+ parent->child = NULL;
+
+ if (del_cb)
+ del_cb(tmp);
+
+ node_destroy(tmp);
+
+ if (next)
+ tmp = next;
+ else if (parent)
+ tmp = parent;
+ else
+ tmp = NULL;
+ }
+}
+
+struct node * const node_next_sibling(const struct node *node)
+{
+ return node->sibling.next;
+}
+
+struct node * const node_prev_sibling(const struct node *node)
+{
+ return node->sibling.prev;
+}
+
+void node_set_mode(struct node *node, int mode)
+{
+ node->mode = mode;
+}
+
+void node_set_data(struct node *node, void *data)
+{
+ node->data = data;
+}
+
+void node_set_type(struct node *node, enum node_type type)
+{
+ node->type = type;
+}
+
+struct node * const node_child(const struct node *node)
+{
+ return node->child;
+}
+
+struct node * const node_parent(const struct node *node)
+{
+ return node->parent;
+}
+
+const int const node_mode(const struct node *node)
+{
+ return node->mode;
+}
+
+void * const node_data(const struct node *node)
+{
+ return node->data;
+}
+
+const enum node_type const node_type(const struct node *node)
+{
+ return node->type;
+}
+
+const char * const node_name(const struct node *node)
+{
+ return node->name;
+}
+
+void node_set_age(struct node *node, int age)
+{
+ node->age = age;
+}
+
+int node_age(struct node *node)
+{
+ return node->age;
+}
+
+/* End of a file */