tizen beta release
authorKibum Kim <kb0929.kim@samsung.com>
Mon, 27 Feb 2012 12:15:50 +0000 (21:15 +0900)
committerKibum Kim <kb0929.kim@samsung.com>
Mon, 27 Feb 2012 12:15:50 +0000 (21:15 +0900)
98 files changed:
CMakeLists.txt [new file with mode: 0755]
LICENSE [new file with mode: 0644]
NOTICE [new file with mode: 0644]
build-util/API-generator.c [new file with mode: 0755]
build-util/DB-schema-gen.c [new file with mode: 0755]
build-util/Makefile [new file with mode: 0755]
build-util/generator.sh [new file with mode: 0755]
contacts-service.pc.in [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/contacts-service-bin.install.in [new file with mode: 0644]
debian/contacts-service-bin.postinst.in [new file with mode: 0755]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/dirs [new file with mode: 0644]
debian/docs [new file with mode: 0644]
debian/libcontacts-service-dev.install.in [new file with mode: 0644]
debian/libcontacts-service.install.in [new file with mode: 0644]
debian/libcontacts-service.postinst.in [new file with mode: 0755]
debian/rules [new file with mode: 0755]
helper/CMakeLists.txt [new file with mode: 0755]
helper/contacts-svc-helper.sh [new file with mode: 0755]
helper/helper-socket.c [new file with mode: 0755]
helper/helper-socket.h [new file with mode: 0755]
helper/internal.h [new file with mode: 0755]
helper/localize.c [new file with mode: 0755]
helper/localize.h [new file with mode: 0755]
helper/main.c [new file with mode: 0755]
helper/normalize.c [new file with mode: 0755]
helper/normalize.h [new file with mode: 0755]
helper/schema-recovery.c [new file with mode: 0755]
helper/schema-recovery.h [new file with mode: 0755]
helper/sim.c [new file with mode: 0755]
helper/sim.h [new file with mode: 0755]
helper/sqlite.c [new file with mode: 0755]
helper/sqlite.h [new file with mode: 0755]
helper/utils.c [new file with mode: 0755]
helper/utils.h [new file with mode: 0755]
image/SLP_ContactsService_PG_image001.PNG [new file with mode: 0755]
include/ContactsService_PG.h [new file with mode: 0755]
include/contacts-svc-struct.head [new file with mode: 0755]
include/contacts-svc-struct.tail [new file with mode: 0755]
include/contacts-svc-sub.head [new file with mode: 0755]
include/contacts-svc-sub.tail [new file with mode: 0755]
include/contacts-svc.head [new file with mode: 0755]
include/contacts-svc.tail [new file with mode: 0644]
packaging/contacts-service.spec [new file with mode: 0644]
schema.sql [new file with mode: 0755]
src/cts-addressbook.c [new file with mode: 0755]
src/cts-addressbook.h [new file with mode: 0755]
src/cts-contact.c [new file with mode: 0755]
src/cts-contact.h [new file with mode: 0755]
src/cts-errors.h [new file with mode: 0755]
src/cts-favorite.c [new file with mode: 0755]
src/cts-favorite.h [new file with mode: 0755]
src/cts-group.c [new file with mode: 0755]
src/cts-group.h [new file with mode: 0755]
src/cts-inotify.c [new file with mode: 0755]
src/cts-inotify.h [new file with mode: 0755]
src/cts-internal.h [new file with mode: 0755]
src/cts-list-info.c [new file with mode: 0755]
src/cts-list.c [new file with mode: 0755]
src/cts-list.h [new file with mode: 0755]
src/cts-normalize.c [new file with mode: 0755]
src/cts-normalize.h [new file with mode: 0755]
src/cts-phonelog.c [new file with mode: 0755]
src/cts-phonelog.h [new file with mode: 0755]
src/cts-pthread.c [new file with mode: 0755]
src/cts-pthread.h [new file with mode: 0755]
src/cts-schema.h [new file with mode: 0755]
src/cts-service.c [new file with mode: 0755]
src/cts-service.h [new file with mode: 0755]
src/cts-socket.c [new file with mode: 0755]
src/cts-socket.h [new file with mode: 0755]
src/cts-sqlite.c [new file with mode: 0755]
src/cts-sqlite.h [new file with mode: 0755]
src/cts-struct-ext.c [new file with mode: 0755]
src/cts-struct-ext.h [new file with mode: 0755]
src/cts-struct.c [new file with mode: 0755]
src/cts-struct.h [new file with mode: 0755]
src/cts-types.c [new file with mode: 0755]
src/cts-types.h [new file with mode: 0755]
src/cts-utils.c [new file with mode: 0755]
src/cts-utils.h [new file with mode: 0755]
src/cts-vcard-file.c [new file with mode: 0755]
src/cts-vcard-file.h [new file with mode: 0755]
src/cts-vcard.c [new file with mode: 0755]
src/cts-vcard.h [new file with mode: 0755]
test/Makefile [new file with mode: 0755]
test/SIMimport-test.c [new file with mode: 0755]
test/addressbook-test.c [new file with mode: 0755]
test/change-noti-test.c [new file with mode: 0755]
test/contact-test.c [new file with mode: 0755]
test/group-test.c [new file with mode: 0755]
test/phonelog-test.c [new file with mode: 0755]
test/timetest.c [new file with mode: 0755]
test/timetest.h [new file with mode: 0755]
test/vcard2contact-test.c [new file with mode: 0755]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..2e79af0
--- /dev/null
@@ -0,0 +1,63 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(contacts-service C)
+
+#IF("${CMAKE_BUILD_TYPE}" STREQUAL "")
+#      SET(CMAKE_BUILD_TYPE "Release")
+#ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "")
+#MESSAGE("Build type: ${CMAKE_BUILD_TYPE}")
+
+SET(DEST_INCLUDE_DIR "include/contacts-svc")
+SET(SRC_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include")
+
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(EXEC_PREFIX "\${prefix}")
+SET(LIBDIR "\${prefix}/lib")
+SET(INCLUDEDIR "\${prefix}/${DEST_INCLUDE_DIR}")
+SET(VERSION_MAJOR 0)
+SET(VERSION "${VERSION_MAJOR}.5.2")
+
+EXECUTE_PROCESS(COMMAND build-util/generator.sh)
+
+#INCLUDE_DIRECTORIES(${SRC_INCLUDE_DIR})
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -I${SRC_INCLUDE_DIR}")
+
+FILE(GLOB SRCS src/*.c)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs REQUIRED glib-2.0 sqlite3 vconf dlog db-util)
+
+FOREACH(flag ${pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+#SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+#SET(CMAKE_C_FLAGS_RELEASE "-mabi=aapcs-linux -march=armv7-a -msoft-float -O2")
+
+ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"")
+
+ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS})
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR})
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${VERSION})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} -lpthread)
+
+CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY)
+SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
+       "${PROJECT_NAME}.pc;include/contacts-svc-sub.h;include/contacts-svc.h;include/contacts-svc-struct.h;helper/schema.h")
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION lib)
+INSTALL(FILES ${PROJECT_NAME}.pc DESTINATION lib/pkgconfig)
+
+FILE(GLOB HEADER_FILES ${SRC_INCLUDE_DIR}/contacts-svc*.h)
+INSTALL(FILES ${HEADER_FILES} DESTINATION ${DEST_INCLUDE_DIR})
+INSTALL(FILES ${SRC_INCLUDE_DIR}/ContactsService_PG.h DESTINATION ${DEST_INCLUDE_DIR})
+
+FILE(GLOB NOTI_FILES ${CMAKE_SOURCE_DIR}/.CONTACTS_SVC_*_CHANGED)
+INSTALL(FILES ${NOTI_FILES} DESTINATION /opt/data/contacts-svc)
+
+INSTALL(DIRECTORY DESTINATION /opt/data/contacts-svc/img/vcard)
+
+ADD_SUBDIRECTORY(helper)
+
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..19c4054
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,204 @@
+Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.\r
+\r
+                                 Apache License\r
+                           Version 2.0, January 2004\r
+                        http://www.apache.org/licenses/\r
+\r
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r
+\r
+   1. Definitions.\r
+\r
+      "License" shall mean the terms and conditions for use, reproduction,\r
+      and distribution as defined by Sections 1 through 9 of this document.\r
+\r
+      "Licensor" shall mean the copyright owner or entity authorized by\r
+      the copyright owner that is granting the License.\r
+\r
+      "Legal Entity" shall mean the union of the acting entity and all\r
+      other entities that control, are controlled by, or are under common\r
+      control with that entity. For the purposes of this definition,\r
+      "control" means (i) the power, direct or indirect, to cause the\r
+      direction or management of such entity, whether by contract or\r
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r
+      outstanding shares, or (iii) beneficial ownership of such entity.\r
+\r
+      "You" (or "Your") shall mean an individual or Legal Entity\r
+      exercising permissions granted by this License.\r
+\r
+      "Source" form shall mean the preferred form for making modifications,\r
+      including but not limited to software source code, documentation\r
+      source, and configuration files.\r
+\r
+      "Object" form shall mean any form resulting from mechanical\r
+      transformation or translation of a Source form, including but\r
+      not limited to compiled object code, generated documentation,\r
+      and conversions to other media types.\r
+\r
+      "Work" shall mean the work of authorship, whether in Source or\r
+      Object form, made available under the License, as indicated by a\r
+      copyright notice that is included in or attached to the work\r
+      (an example is provided in the Appendix below).\r
+\r
+      "Derivative Works" shall mean any work, whether in Source or Object\r
+      form, that is based on (or derived from) the Work and for which the\r
+      editorial revisions, annotations, elaborations, or other modifications\r
+      represent, as a whole, an original work of authorship. For the purposes\r
+      of this License, Derivative Works shall not include works that remain\r
+      separable from, or merely link (or bind by name) to the interfaces of,\r
+      the Work and Derivative Works thereof.\r
+\r
+      "Contribution" shall mean any work of authorship, including\r
+      the original version of the Work and any modifications or additions\r
+      to that Work or Derivative Works thereof, that is intentionally\r
+      submitted to Licensor for inclusion in the Work by the copyright owner\r
+      or by an individual or Legal Entity authorized to submit on behalf of\r
+      the copyright owner. For the purposes of this definition, "submitted"\r
+      means any form of electronic, verbal, or written communication sent\r
+      to the Licensor or its representatives, including but not limited to\r
+      communication on electronic mailing lists, source code control systems,\r
+      and issue tracking systems that are managed by, or on behalf of, the\r
+      Licensor for the purpose of discussing and improving the Work, but\r
+      excluding communication that is conspicuously marked or otherwise\r
+      designated in writing by the copyright owner as "Not a Contribution."\r
+\r
+      "Contributor" shall mean Licensor and any individual or Legal Entity\r
+      on behalf of whom a Contribution has been received by Licensor and\r
+      subsequently incorporated within the Work.\r
+\r
+   2. Grant of Copyright License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      copyright license to reproduce, prepare Derivative Works of,\r
+      publicly display, publicly perform, sublicense, and distribute the\r
+      Work and such Derivative Works in Source or Object form.\r
+\r
+   3. Grant of Patent License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      (except as stated in this section) patent license to make, have made,\r
+      use, offer to sell, sell, import, and otherwise transfer the Work,\r
+      where such license applies only to those patent claims licensable\r
+      by such Contributor that are necessarily infringed by their\r
+      Contribution(s) alone or by combination of their Contribution(s)\r
+      with the Work to which such Contribution(s) was submitted. If You\r
+      institute patent litigation against any entity (including a\r
+      cross-claim or counterclaim in a lawsuit) alleging that the Work\r
+      or a Contribution incorporated within the Work constitutes direct\r
+      or contributory patent infringement, then any patent licenses\r
+      granted to You under this License for that Work shall terminate\r
+      as of the date such litigation is filed.\r
+\r
+   4. Redistribution. You may reproduce and distribute copies of the\r
+      Work or Derivative Works thereof in any medium, with or without\r
+      modifications, and in Source or Object form, provided that You\r
+      meet the following conditions:\r
+\r
+      (a) You must give any other recipients of the Work or\r
+          Derivative Works a copy of this License; and\r
+\r
+      (b) You must cause any modified files to carry prominent notices\r
+          stating that You changed the files; and\r
+\r
+      (c) You must retain, in the Source form of any Derivative Works\r
+          that You distribute, all copyright, patent, trademark, and\r
+          attribution notices from the Source form of the Work,\r
+          excluding those notices that do not pertain to any part of\r
+          the Derivative Works; and\r
+\r
+      (d) If the Work includes a "NOTICE" text file as part of its\r
+          distribution, then any Derivative Works that You distribute must\r
+          include a readable copy of the attribution notices contained\r
+          within such NOTICE file, excluding those notices that do not\r
+          pertain to any part of the Derivative Works, in at least one\r
+          of the following places: within a NOTICE text file distributed\r
+          as part of the Derivative Works; within the Source form or\r
+          documentation, if provided along with the Derivative Works; or,\r
+          within a display generated by the Derivative Works, if and\r
+          wherever such third-party notices normally appear. The contents\r
+          of the NOTICE file are for informational purposes only and\r
+          do not modify the License. You may add Your own attribution\r
+          notices within Derivative Works that You distribute, alongside\r
+          or as an addendum to the NOTICE text from the Work, provided\r
+          that such additional attribution notices cannot be construed\r
+          as modifying the License.\r
+\r
+      You may add Your own copyright statement to Your modifications and\r
+      may provide additional or different license terms and conditions\r
+      for use, reproduction, or distribution of Your modifications, or\r
+      for any such Derivative Works as a whole, provided Your use,\r
+      reproduction, and distribution of the Work otherwise complies with\r
+      the conditions stated in this License.\r
+\r
+   5. Submission of Contributions. Unless You explicitly state otherwise,\r
+      any Contribution intentionally submitted for inclusion in the Work\r
+      by You to the Licensor shall be under the terms and conditions of\r
+      this License, without any additional terms or conditions.\r
+      Notwithstanding the above, nothing herein shall supersede or modify\r
+      the terms of any separate license agreement you may have executed\r
+      with Licensor regarding such Contributions.\r
+\r
+   6. Trademarks. This License does not grant permission to use the trade\r
+      names, trademarks, service marks, or product names of the Licensor,\r
+      except as required for reasonable and customary use in describing the\r
+      origin of the Work and reproducing the content of the NOTICE file.\r
+\r
+   7. Disclaimer of Warranty. Unless required by applicable law or\r
+      agreed to in writing, Licensor provides the Work (and each\r
+      Contributor provides its Contributions) on an "AS IS" BASIS,\r
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r
+      implied, including, without limitation, any warranties or conditions\r
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r
+      PARTICULAR PURPOSE. You are solely responsible for determining the\r
+      appropriateness of using or redistributing the Work and assume any\r
+      risks associated with Your exercise of permissions under this License.\r
+\r
+   8. Limitation of Liability. In no event and under no legal theory,\r
+      whether in tort (including negligence), contract, or otherwise,\r
+      unless required by applicable law (such as deliberate and grossly\r
+      negligent acts) or agreed to in writing, shall any Contributor be\r
+      liable to You for damages, including any direct, indirect, special,\r
+      incidental, or consequential damages of any character arising as a\r
+      result of this License or out of the use or inability to use the\r
+      Work (including but not limited to damages for loss of goodwill,\r
+      work stoppage, computer failure or malfunction, or any and all\r
+      other commercial damages or losses), even if such Contributor\r
+      has been advised of the possibility of such damages.\r
+\r
+   9. Accepting Warranty or Additional Liability. While redistributing\r
+      the Work or Derivative Works thereof, You may choose to offer,\r
+      and charge a fee for, acceptance of support, warranty, indemnity,\r
+      or other liability obligations and/or rights consistent with this\r
+      License. However, in accepting such obligations, You may act only\r
+      on Your own behalf and on Your sole responsibility, not on behalf\r
+      of any other Contributor, and only if You agree to indemnify,\r
+      defend, and hold each Contributor harmless for any liability\r
+      incurred by, or claims asserted against, such Contributor by reason\r
+      of your accepting any such warranty or additional liability.\r
+\r
+   END OF TERMS AND CONDITIONS\r
+\r
+   APPENDIX: How to apply the Apache License to your work.\r
+\r
+      To apply the Apache License to your work, attach the following\r
+      boilerplate notice, with the fields enclosed by brackets "[]"\r
+      replaced with your own identifying information. (Don't include\r
+      the brackets!)  The text should be enclosed in the appropriate\r
+      comment syntax for the file format. We also recommend that a\r
+      file or class name and description of purpose be included on the\r
+      same "printed page" as the copyright notice for easier\r
+      identification within third-party archives.\r
+\r
+   Copyright [yyyy] [name of copyright owner]\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
diff --git a/NOTICE b/NOTICE
new file mode 100644 (file)
index 0000000..fd4209d
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1 @@
+Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
diff --git a/build-util/API-generator.c b/build-util/API-generator.c
new file mode 100755 (executable)
index 0000000..ee62026
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+       FILE *fp;
+       char *line = NULL;
+       size_t len = 0;
+       ssize_t read;
+
+       fp = fopen(argv[1], "r");
+       if (fp == NULL)
+               exit(EXIT_FAILURE);
+
+       while ((read = getline(&line, &len, fp)) != -1) {
+               if (len >= 6 && '/'==line[0]
+                               && '/'==line[1]
+                               && '<'==line[2]
+                               && '!'==line[3]
+                               && '-'==line[4]
+                               && '-'==line[5])
+                       break;
+       }
+
+       while ((read = getline(&line, &len, fp)) != -1) {
+               if (len >= 5 && '/'==line[0]
+                               && '/'==line[1]
+                               && '-'==line[2]
+                               && '-'==line[3]
+                               && '>'==line[4])
+                       break;
+               printf("%s", line);
+       }
+
+       free(line);
+       exit(EXIT_SUCCESS);
+}
+
diff --git a/build-util/DB-schema-gen.c b/build-util/DB-schema-gen.c
new file mode 100755 (executable)
index 0000000..05287cb
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+       FILE *fp;
+       int c;
+
+       fp = fopen(argv[1], "r");
+       if (fp == NULL)
+               exit(EXIT_FAILURE);
+
+       do{
+               c = fgetc(fp);
+               switch (c)
+               {
+               case '\n':
+                       printf("\\\n");
+                       break;
+               case '-':
+                       if ('-' == (c = fgetc(fp))) {
+                               while ('\n' != c && EOF != c)
+                                       c = fgetc(fp);
+                               printf("\\\n");
+                       }
+                       else printf("-%c",c);
+                       break;
+               case EOF:
+                       break;
+               default:
+                       printf("%c",c);
+                       break;
+               }
+       }while(EOF != c);
+
+       exit(EXIT_SUCCESS);
+}
+
diff --git a/build-util/Makefile b/build-util/Makefile
new file mode 100755 (executable)
index 0000000..70b2727
--- /dev/null
@@ -0,0 +1,22 @@
+CC = gcc
+
+REQUIRED_PKG =
+CFLAGS = -g -Wall #-fprofile-arcs -ftest-coverage
+LDFLAGS =
+ifdef REQUIRED_PKG
+       CFLAGS += `pkg-config --cflags $(REQUIRED_PKG)`
+       LDFLAGS += `pkg-config --libs $(REQUIRED_PKG)`
+endif
+
+SRCS = $(wildcard *.c)
+OBJECTS = $(SRCS:.c=.o)
+TARGETS = $(OBJECTS:.o=)
+
+all: $(TARGETS)
+
+% : %.o
+       $(CC) $(LDFLAGS) -o $@ $<
+
+clean:
+       rm -rf $(OBJECTS) $(TARGETS)
+
diff --git a/build-util/generator.sh b/build-util/generator.sh
new file mode 100755 (executable)
index 0000000..0bc0730
--- /dev/null
@@ -0,0 +1,61 @@
+#
+# Contacts Service
+#
+# Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+#
+# Contact: Youngjae Shin <yj99.shin@samsung.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#!/bin/sh
+
+echo "###### API Generator #####"
+
+cd build-util
+make
+
+#contacts-svc.h
+cat ../include/contacts-svc.head > ../include/contacts-svc.h
+./API-generator ../src/cts-service.h >> ../include/contacts-svc.h
+./API-generator ../src/cts-errors.h >> ../include/contacts-svc.h
+./API-generator ../src/cts-addressbook.h >> ../include/contacts-svc.h
+./API-generator ../src/cts-contact.h >> ../include/contacts-svc.h
+./API-generator ../src/cts-normalize.h >> ../include/contacts-svc.h
+./API-generator ../src/cts-list.h >> ../include/contacts-svc.h
+./API-generator ../src/cts-utils.h >> ../include/contacts-svc.h
+./API-generator ../src/cts-vcard.h >> ../include/contacts-svc.h
+cat ../include/contacts-svc.tail >> ../include/contacts-svc.h
+
+# contacts-svc-struct.h
+cat ../include/contacts-svc-struct.head > ../include/contacts-svc-struct.h
+./API-generator ../src/cts-struct.h >> ../include/contacts-svc-struct.h
+./API-generator ../src/cts-struct-ext.h >> ../include/contacts-svc-struct.h
+cat ../include/contacts-svc-struct.tail >> ../include/contacts-svc-struct.h
+
+# contacts-svc-sub.h
+cat ../include/contacts-svc-sub.head > ../include/contacts-svc-sub.h
+./API-generator ../src/cts-phonelog.h >> ../include/contacts-svc-sub.h
+./API-generator ../src/cts-favorite.h >> ../include/contacts-svc-sub.h
+./API-generator ../src/cts-group.h >> ../include/contacts-svc-sub.h
+./API-generator ../src/cts-im.h >> ../include/contacts-svc-sub.h
+./API-generator ../src/cts-types.h >> ../include/contacts-svc-sub.h
+cat ../include/contacts-svc-sub.tail >> ../include/contacts-svc-sub.h
+
+# Schema
+echo "static const char *schema_query = \"\\" > ../helper/schema.h
+./DB-schema-gen ../schema.sql >> ../helper/schema.h
+echo \"\; >> ../helper/schema.h
+
+
+make clean
diff --git a/contacts-service.pc.in b/contacts-service.pc.in
new file mode 100644 (file)
index 0000000..cdaf2a5
--- /dev/null
@@ -0,0 +1,13 @@
+# Package Information for pkg-config
+
+prefix=@PREFIX@
+exec_prefix=@EXEC_PREFIX@
+libdir=@LIBDIR@
+includedir=@INCLUDEDIR@
+
+Name: @PROJECT_NAME@
+Description: @PROJECT_NAME@ library
+Version: @VERSION@
+Requires: glib-2.0
+Libs: -L${libdir} -l@PROJECT_NAME@
+Cflags: -I${includedir}
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..04ff60e
--- /dev/null
@@ -0,0 +1,7 @@
+contacts-service (0.5.2-37) unstable; urgency=low
+
+  * release
+  * Git: pkgs/c/contacts-service
+  * Tag: contacts-service_0.5.2-37
+
+ -- Youngjae Shin <yj99.shin@samsung.com>  Tue, 21 Feb 2012 18:36:56 +0900
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..7ed6ff8
--- /dev/null
@@ -0,0 +1 @@
+5
diff --git a/debian/contacts-service-bin.install.in b/debian/contacts-service-bin.install.in
new file mode 100644 (file)
index 0000000..5549ed0
--- /dev/null
@@ -0,0 +1,2 @@
+@PREFIX@/bin/*
+/etc/*
diff --git a/debian/contacts-service-bin.postinst.in b/debian/contacts-service-bin.postinst.in
new file mode 100755 (executable)
index 0000000..52e46f0
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+if [ ! -d /opt/dbspace ]
+then
+       mkdir -p /opt/dbspace
+fi
+
+contacts-svc-helper schema
+
+if [ "$USER" = "root" ]
+then
+# Change file owner
+   chown :6005 /opt/dbspace/.contacts-svc.db
+   chown :6005 /opt/dbspace/.contacts-svc.db-journal
+
+   chown root:root @PREFIX@/bin/contacts-svc-helper*
+   chown root:root /etc/rc.d/init.d/contacts-svc-helper.sh
+fi
+
+# Change file permissions
+# chmod 755 /usr/bin/contacts-svc-helper
+
+chmod 660 /opt/dbspace/.contacts-svc.db
+chmod 660 /opt/dbspace/.contacts-svc.db-journal
+
+chmod 755 /etc/rc.d/init.d/contacts-svc-helper.sh
+
+vconftool set -t int db/service/contacts/default_lang 1
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..e061d95
--- /dev/null
@@ -0,0 +1,33 @@
+Source: contacts-service
+Section: devel
+Priority: extra
+Maintainer: Youngjae Shin <yj99.shin@samsung.com>, Donghee Ye <donghee.ye@samsung.com>
+Build-Depends: debhelper (>= 5), libslp-db-util-dev, libsqlite3-dev, libglib2.0-dev, dlog-dev, libvconf-dev, libvconf-keys-dev, libslp-tapi-dev, libicu-dev
+Standards-Version: 3.7.2
+Homepage: N/A
+
+Package: libcontacts-service-dev
+Section: devel
+Architecture: any
+Depends: libcontacts-service (= ${Source-Version}), libglib2.0-dev
+Description: contacts service Library (development)
+XB-Generate-Docs: yes
+
+Package: libcontacts-service
+Section: libs
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Recommends: contacts-service-bin (= ${Source-Version})
+Description: contacts service Library (Library)
+
+Package: contacts-service-bin
+Section: devel
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: contacts service binary : contacts-svc-helper
+
+Package: libcontacts-service-dbg
+Section: debug
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, libcontacts-service (= ${Source-Version})
+Description: contacts service Library (unstripped)
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..74c3188
--- /dev/null
@@ -0,0 +1,7 @@
+Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the Apache License version 2.0.
+
+The full text of the Apache 2.0 can be found in
+/usr/share/common-licenses.
diff --git a/debian/dirs b/debian/dirs
new file mode 100644 (file)
index 0000000..ca882bb
--- /dev/null
@@ -0,0 +1,2 @@
+usr/bin
+usr/sbin
diff --git a/debian/docs b/debian/docs
new file mode 100644 (file)
index 0000000..a0f0008
--- /dev/null
@@ -0,0 +1 @@
+CMakeLists.txt
diff --git a/debian/libcontacts-service-dev.install.in b/debian/libcontacts-service-dev.install.in
new file mode 100644 (file)
index 0000000..1bcdd80
--- /dev/null
@@ -0,0 +1,4 @@
+@PREFIX@/lib/*.so
+@PREFIX@/include/contacts-svc/*.h
+@PREFIX@/lib/pkgconfig/contacts-service.pc
+
diff --git a/debian/libcontacts-service.install.in b/debian/libcontacts-service.install.in
new file mode 100644 (file)
index 0000000..348fb98
--- /dev/null
@@ -0,0 +1,2 @@
+@PREFIX@/lib/*.so.*
+/opt/*
diff --git a/debian/libcontacts-service.postinst.in b/debian/libcontacts-service.postinst.in
new file mode 100755 (executable)
index 0000000..14aef55
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+if [ "$USER" = "root" ]
+then
+# Change file owner
+   chown root:root @PREFIX@/lib/libcontacts-service.so.*
+   chown :6005 -R /opt/data/contacts-svc/img
+   chown :6005 /opt/data/contacts-svc/.CONTACTS_SVC_*
+   vconftool set -t int db/service/contacts/name_sorting_order 0 -g 6005
+   vconftool set -t int db/service/contacts/name_display_order 0 -g 6005
+else
+   vconftool set -t int db/service/contacts/name_sorting_order 0
+   vconftool set -t int db/service/contacts/name_display_order 0
+fi
+
+# Change file permissions
+# chmod 644 /usr/lib/libcontacts-service.so
+chmod 660 /opt/data/contacts-svc/.CONTACTS_SVC_*
+chmod 770 -R /opt/data/contacts-svc/img
+
+echo "Done"
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..f2b94ce
--- /dev/null
@@ -0,0 +1,115 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+CFLAGS += -Wall
+LDFLAGS ?=
+PREFIX ?= /usr
+DATADIR ?= /opt
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+       CFLAGS += -O0
+else
+       CFLAGS += -O2
+endif
+
+LDFLAGS += -Wl,--hash-style=both -Wl,--rpath=$(PREFIX)/lib -Wl,--as-needed
+
+configure: configure-stamp
+configure-stamp:
+       dh_testdir
+       # Add here commands to configure the package.
+       CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" cmake . -DCMAKE_INSTALL_PREFIX=$(PREFIX)
+
+       touch configure-stamp
+
+build: build-stamp
+
+build-stamp: configure-stamp
+       dh_testdir
+
+       # Add here commands to compile the package.
+       $(MAKE)
+
+       for f in `find $(CURDIR)/debian/ -name "*.in"`; do \
+               cat $$f > $${f%.in}; \
+               sed -i -e "s#@PREFIX@#$(PREFIX)#g" $${f%.in}; \
+               sed -i -e "s#@DATADIR@#$(DATADIR)#g" $${f%.in}; \
+       done
+
+
+       touch $@
+
+clean:
+       dh_testdir
+       dh_testroot
+       rm -f build-stamp configure-stamp
+
+       # Add here commands to clean up after the build process.
+       -$(MAKE) clean
+       rm -rf CMakeCache.txt CMakeFiles cmake_install.cmake Makefile install_manifest.txt
+       cd helper; rm -rf CMakeCache.txt CMakeFiles cmake_install.cmake Makefile install_manifest.txt
+
+       for f in `find $(CURDIR)/debian/ -name "*.in"`; do \
+               rm -f $${f%.in}; \
+       done
+
+       dh_clean
+
+install: build
+       dh_testdir
+       dh_testroot
+       dh_prep
+       dh_installdirs
+
+       # Add here commands to install the package.
+       $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install
+       mkdir -p $(CURDIR)/debian/tmp/etc/rc.d/rc3.d/
+       mkdir -p $(CURDIR)/debian/tmp/etc/rc.d/rc5.d/
+       ln -s ../init.d/contacts-svc-helper.sh $(CURDIR)/debian/tmp/etc/rc.d/rc3.d/S50contacts-svc-helper
+       ln -s ../init.d/contacts-svc-helper.sh $(CURDIR)/debian/tmp/etc/rc.d/rc5.d/S50contacts-svc-helper
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+       dh_testdir
+       dh_testroot
+#      dh_installchangelogs
+#      dh_installdocs
+       dh_installexamples
+       dh_install --sourcedir=debian/tmp
+#      dh_installmenu
+#      dh_installdebconf
+#      dh_installlogrotate
+#      dh_installemacsen
+#      dh_installpam
+#      dh_installmime
+#      dh_python
+#      dh_installinit
+#      dh_installcron
+#      dh_installinfo
+       dh_installman
+       dh_link
+       dh_strip --dbg-package=libcontacts-service-dbg
+       dh_compress
+       dh_fixperms
+#      dh_perl
+       dh_makeshlibs
+       dh_installdeb
+       dh_shlibdeps
+       dh_gencontrol
+       dh_md5sums
+       dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
diff --git a/helper/CMakeLists.txt b/helper/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..594c888
--- /dev/null
@@ -0,0 +1,24 @@
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src)
+LINK_DIRECTORIES(${CMAKE_BINARY_DIR})
+
+SET(TARGET contacts-svc-helper)
+
+FILE(GLOB SRCS *.c)
+#SET(SRCS main.c schema-recovery.c)
+
+pkg_check_modules(helper_pkgs REQUIRED tapi icu-i18n)
+
+UNSET(EXTRA_CFLAGS)
+FOREACH(flag ${helper_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+#SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+
+ADD_EXECUTABLE(${TARGET} ${SRCS})
+SET_TARGET_PROPERTIES(${TARGET} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS})
+TARGET_LINK_LIBRARIES(${TARGET} ${PROJECT_NAME} ${helper_pkgs_LDFLAGS})
+
+INSTALL(TARGETS ${TARGET} DESTINATION bin)
+INSTALL(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/contacts-svc-helper.sh DESTINATION /etc/rc.d/init.d)
diff --git a/helper/contacts-svc-helper.sh b/helper/contacts-svc-helper.sh
new file mode 100755 (executable)
index 0000000..8966589
--- /dev/null
@@ -0,0 +1 @@
+/usr/bin/contacts-svc-helper &
diff --git a/helper/helper-socket.c b/helper/helper-socket.c
new file mode 100755 (executable)
index 0000000..f66f0b1
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <unistd.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <contacts-svc.h>
+
+#include "internal.h"
+#include "cts-schema.h"
+#include "cts-sqlite.h"
+#include "cts-socket.h"
+#include "helper-socket.h"
+#include "sim.h"
+#include "normalize.h"
+#include "utils.h"
+
+
+static inline int helper_safe_write(int fd, char *buf, int buf_size)
+{
+       int ret, writed=0;
+       while (buf_size) {
+               ret = write(fd, buf+writed, buf_size);
+               if (-1 == ret) {
+                       if (EINTR == errno)
+                               continue;
+                       else
+                               return ret;
+               }
+               writed += ret;
+               buf_size -= ret;
+       }
+       return writed;
+}
+
+
+static inline int helper_safe_read(int fd, char *buf, int buf_size)
+{
+       int ret, read_size=0;
+       while (buf_size) {
+               ret = read(fd, buf+read_size, buf_size);
+               if (-1 == ret) {
+                       if (EINTR == errno)
+                               continue;
+                       else
+                               return ret;
+               }
+               read_size += ret;
+               buf_size -= ret;
+       }
+       return read_size;
+}
+
+
+static void helper_discard_msg(int fd, int size)
+{
+       int ret;
+       char dummy[CTS_SQL_MAX_LEN];
+
+       while (size) {
+               if (sizeof(dummy) < size) {
+                       ret = read(fd, dummy, sizeof(dummy));
+                       if (-1 == ret) {
+                               if (EINTR == errno)
+                                       continue;
+                               else
+                                       return;
+                       }
+                       size -= ret;
+               }
+               else {
+                       ret = read(fd, dummy, size);
+                       if (-1 == ret) {
+                               if (EINTR == errno)
+                                       continue;
+                               else
+                                       return;
+                       }
+                       size -= ret;
+               }
+       }
+}
+
+int helper_socket_return(GIOChannel *src, int value, int attach_num, int *attach_size)
+{
+       int ret;
+       cts_socket_msg msg={0};
+
+       h_retvm_if(CTS_ERR_SOCKET_FAILED == value, value, "Socket has problems");
+       h_retvm_if(CTS_REQUEST_MAX_ATTACH < attach_num, CTS_ERR_ARG_INVALID,
+                       "Invalid msg(attach_num = %d)", attach_num);
+
+       msg.type = CTS_REQUEST_RETURN_VALUE;
+       msg.val = value;
+       msg.attach_num = attach_num;
+
+       memcpy(msg.attach_sizes, attach_size, attach_num * sizeof(int));
+
+       HELPER_DBG("fd = %d, MSG_TYPE=%d, MSG_VAL=%d, MSG_ATTACH_NUM=%d,"
+                       "MSG_ATTACH1=%d, MSG_ATTACH2=%d, MSG_ATTACH3=%d, MSG_ATTACH4=%d",
+                       g_io_channel_unix_get_fd(src), msg.type, msg.val, msg.attach_num,
+                       msg.attach_sizes[0], msg.attach_sizes[1], msg.attach_sizes[2],
+                       msg.attach_sizes[3]);
+
+       ret = helper_safe_write(g_io_channel_unix_get_fd(src), (char *)&msg, sizeof(msg));
+       h_retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED,
+                       "helper_safe_write() Failed(errno = %d)", errno);
+
+       return CTS_SUCCESS;
+}
+
+static void helper_handle_import_sim(GIOChannel *src)
+{
+       int ret;
+
+       ret = helper_sim_read_pb_record(src);
+       if (CTS_SUCCESS != ret) {
+               ERR("helper_sim_read_pb_record() Failed(%d)", ret);
+               helper_socket_return(src, ret, 0, NULL);
+       }
+}
+
+static int helper_normalize(GIOChannel *src, int read_size,
+               char *dest, int dest_size)
+{
+       int ret=CTS_SUCCESS;
+       gsize len;
+       GError *gerr = NULL;
+       char receiver[CTS_SQL_MAX_LEN];
+
+       g_io_channel_read_chars(src, receiver, read_size, &len, &gerr);
+       if (gerr) {
+               ERR("g_io_channel_read_chars() Failed(%s)", gerr->message);
+               g_error_free(gerr);
+               return CTS_ERR_SOCKET_FAILED;
+       }
+       HELPER_DBG("Receiver = %s(%d), read_size = %d", receiver, len, read_size);
+
+       if (len) {
+               receiver[len] = '\0';
+               ret = helper_normalize_str(receiver, dest, dest_size);
+               h_retvm_if(ret < CTS_SUCCESS, ret, "helper_normalize_str() Failed(%d)", ret);
+               HELPER_DBG("Normalized text of %s = %s(%d)", receiver, dest, strlen(dest));
+       }
+       return ret;
+}
+
+static int helper_collation(GIOChannel *src, int read_size,
+               char *dest, int dest_size)
+{
+       int ret = CTS_SUCCESS;
+       gsize len;
+       GError *gerr = NULL;
+       char receiver[CTS_SQL_MAX_LEN];
+
+       g_io_channel_read_chars(src, receiver, read_size, &len, &gerr);
+       if (gerr) {
+               ERR("g_io_channel_read_chars() Failed(%s)", gerr->message);
+               g_error_free(gerr);
+               return CTS_ERR_SOCKET_FAILED;
+       }
+       HELPER_DBG("Receiver = %s(%d), read_size = %d", receiver, len, read_size);
+
+       if (len) {
+               receiver[len] = '\0';
+               ret = helper_collation_str(receiver, dest, dest_size);
+               h_retvm_if(ret < CTS_SUCCESS, ret, "helper_collation_str() Failed(%d)", ret);
+               HELPER_DBG("Sortkey of %s : %s, %d", receiver, dest, strlen(dest));
+       }
+       return ret;
+}
+
+static void helper_handle_normalize_str(GIOChannel *src, int size)
+{
+       HELPER_FN_CALL;
+       int str_len, ret;
+       char normalized_str[CTS_SQL_MAX_LEN];
+
+       ret = helper_normalize(src, size, normalized_str, sizeof(normalized_str));
+       if (ret < CTS_SUCCESS) {
+               ERR("helper_normalize() Failed(%d)", ret);
+               helper_socket_return(src, ret, 0, NULL);
+               return;
+       }
+       str_len = strlen(normalized_str);
+
+       ret = helper_socket_return(src, CTS_SUCCESS, 1, &str_len);
+       h_retm_if(CTS_SUCCESS != ret, "helper_socket_return() Failed(%d)", ret);
+       ret = helper_safe_write(g_io_channel_unix_get_fd(src), normalized_str, str_len);
+       h_retm_if(-1 == ret, "helper_safe_write() Failed(errno = %d)", errno);
+}
+
+static void helper_handle_normalize_name(GIOChannel *src, int* sizes)
+{
+       HELPER_FN_CALL;
+       int fd, ret;
+       int lang_type = 0;
+       int msg_size_buf[CTS_REQUEST_MAX_ATTACH]={0};
+       char normalized_first[CTS_SQL_MAX_LEN], normalized_last[CTS_SQL_MAX_LEN];
+       char sortkey[CTS_SQL_MAX_LEN];
+
+       if (sizes[CTS_NN_FIRST])
+       {
+               ret = helper_normalize(src, sizes[CTS_NN_FIRST], normalized_first,
+                               sizeof(normalized_first));
+               if (ret < CTS_SUCCESS) {
+                       ERR("helper_normalize() Failed(%d)", ret);
+                       helper_discard_msg(g_io_channel_unix_get_fd(src),
+                                       sizes[CTS_NN_LAST] + sizes[CTS_NN_SORTKEY]);
+                       helper_socket_return(src, ret, 0, NULL);
+                       return;
+               }
+               lang_type = ret;
+
+               msg_size_buf[CTS_NN_FIRST] = strlen(normalized_first);
+       }
+
+       if (sizes[CTS_NN_LAST])
+       {
+               ret = helper_normalize(src, sizes[CTS_NN_LAST], normalized_last,
+                               sizeof(normalized_last));
+               if (ret < CTS_SUCCESS) {
+                       ERR("helper_normalize() Failed(%d)", ret);
+                       helper_discard_msg(g_io_channel_unix_get_fd(src), sizes[CTS_NN_SORTKEY]);
+                       helper_socket_return(src, ret, 0, NULL);
+                       return;
+               }
+               if (lang_type < ret) lang_type = ret;
+
+               msg_size_buf[CTS_NN_LAST] = strlen(normalized_last);
+       }
+
+       if (sizes[CTS_NN_SORTKEY])
+       {
+               ret = helper_collation(src, sizes[CTS_NN_SORTKEY], sortkey, sizeof(sortkey));
+               if (ret < CTS_SUCCESS) {
+                       ERR("helper_collation() Failed(%d)", ret);
+                       helper_socket_return(src, ret, 0, NULL);
+               }
+               msg_size_buf[CTS_NN_SORTKEY] = strlen(sortkey);
+       }
+
+       ret = helper_socket_return(src, lang_type, 3, msg_size_buf);
+       h_retm_if(CTS_SUCCESS != ret, "helper_socket_return() Failed(%d)", ret);
+
+       fd = g_io_channel_unix_get_fd(src);
+       ret = helper_safe_write(fd, normalized_first, msg_size_buf[0]);
+       h_retm_if(-1 == ret, "helper_safe_write() Failed(errno = %d)", errno);
+       ret = helper_safe_write(fd, normalized_last, msg_size_buf[1]);
+       h_retm_if(-1 == ret, "helper_safe_write() Failed(errno = %d)", errno);
+       ret = helper_safe_write(fd, sortkey, msg_size_buf[2]);
+       h_retm_if(-1 == ret, "helper_safe_write() Failed(errno = %d)", errno);
+}
+
+static gboolean request_handler(GIOChannel *src, GIOCondition condition,
+               gpointer data)
+{
+       int ret;
+       cts_socket_msg msg={0};
+       HELPER_FN_CALL;
+
+       if (G_IO_HUP & condition) {
+               close(g_io_channel_unix_get_fd(src));
+               return FALSE;
+       }
+
+       ret = helper_safe_read(g_io_channel_unix_get_fd(src), (char *)&msg, sizeof(msg));
+       h_retvm_if(-1 == ret, TRUE, "helper_safe_read() Failed(errno = %d)", errno);
+
+       HELPER_DBG("attach number = %d, attach1 = %d, attach2 = %d",
+                       msg.attach_num, msg.attach_sizes[CTS_NN_FIRST],
+                       msg.attach_sizes[CTS_NN_LAST]);
+
+       switch (msg.type)
+       {
+       case CTS_REQUEST_IMPORT_SIM:
+               helper_handle_import_sim(src);
+               break;
+       case CTS_REQUEST_NORMALIZE_STR:
+               if (CTS_NS_ATTACH_NUM != msg.attach_num) {
+                       ERR("Invalid CTS_NS_ATTACH_NUM = %d", msg.attach_num);
+                       helper_socket_return(src, CTS_ERR_MSG_INVALID, 0, NULL);
+               }
+               else
+                       helper_handle_normalize_str(src, msg.attach_sizes[0]);
+               break;
+       case CTS_REQUEST_NORMALIZE_NAME:
+               if (CTS_NN_ATTACH_NUM != msg.attach_num) {
+                       ERR("Invalid CTS_NN_ATTACH_NUM = %d", msg.attach_num);
+                       helper_socket_return(src, CTS_ERR_MSG_INVALID, 0, NULL);
+               }else if (!msg.attach_sizes[CTS_NN_FIRST] && !msg.attach_sizes[CTS_NN_LAST]) {
+                       ERR("No attach names(CTS_NN_FIRST size = %d, CTS_NN_LAST size = %d ",
+                                       msg.attach_sizes[CTS_NN_FIRST], msg.attach_sizes[CTS_NN_LAST]);
+                       helper_socket_return(src, CTS_ERR_MSG_INVALID, 0, NULL);
+               }
+               else
+                       helper_handle_normalize_name(src, msg.attach_sizes);
+               break;
+       default:
+               ERR("Unknown request type(%d)", msg.type);
+               break;
+       }
+       return TRUE;
+}
+
+static gboolean socket_handler(GIOChannel *src,
+               GIOCondition condition, gpointer data)
+{
+       GIOChannel *channel;
+       int client_sockfd, sockfd = (int)data;
+       struct sockaddr_un clientaddr;
+       socklen_t client_len = sizeof(clientaddr);
+
+       HELPER_FN_CALL;
+
+       client_sockfd = accept(sockfd, (struct sockaddr *)&clientaddr, &client_len);
+       h_retvm_if(-1 == client_sockfd, TRUE, "accept() Failed(errno = %d)", errno);
+
+       channel = g_io_channel_unix_new(client_sockfd);
+       g_io_add_watch(channel, G_IO_IN|G_IO_HUP, request_handler, NULL);
+       g_io_channel_unref(channel);
+
+       return TRUE;
+}
+
+int helper_socket_init(void)
+{
+       int sockfd, ret;
+       struct sockaddr_un addr;
+       GIOChannel *gio;
+
+       unlink(CTS_SOCKET_PATH);
+
+       bzero(&addr, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", CTS_SOCKET_PATH);
+
+       sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
+       h_retvm_if(-1 == sockfd, CTS_ERR_SOCKET_FAILED, "socket() Failed(errno = %d)", errno);
+
+       ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
+       h_retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "bind() Failed(errno = %d)", errno);
+
+       chown(CTS_SOCKET_PATH, getuid(), CTS_SECURITY_FILE_GROUP);
+       chmod(CTS_SOCKET_PATH, CTS_SECURITY_DEFAULT_PERMISSION);
+
+       ret = listen(sockfd, 30);
+       h_retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "listen() Failed(errno = %d)", errno);
+
+       gio = g_io_channel_unix_new(sockfd);
+       g_io_add_watch(gio, G_IO_IN, socket_handler, (gpointer)sockfd);
+
+       return CTS_SUCCESS;
+}
diff --git a/helper/helper-socket.h b/helper/helper-socket.h
new file mode 100755 (executable)
index 0000000..9e68698
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_HELPER_SOCKET_H__
+#define __CTS_HELPER_SOCKET_H__
+
+int helper_socket_init(void);
+int helper_socket_return(GIOChannel *src, int value, int attach_num, int *attach_size);
+
+#endif // __CTS_HELPER_SOCKET_H__
+
+
diff --git a/helper/internal.h b/helper/internal.h
new file mode 100755 (executable)
index 0000000..75a20e6
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_HELPER_INTERNAL_H__
+#define __CTS_HELPER_INTERNAL_H__
+
+#include <stdio.h>
+
+#ifndef API
+#define API __attribute__ ((visibility("default")))
+#endif
+
+// Additional Error
+enum {
+       CTS_ERR_NO_DB_FILE = -10000,
+};
+
+// DBUS Information
+#define CTS_DBUS_SERVICE "org.tizen.contacts.service"
+
+#define HELPER_DLOG_OUT
+//#define HELPER_DEBUGGING
+
+#ifdef HELPER_DLOG_OUT
+#define LOG_TAG "CONTACTS_SVC_HELPER"
+#include <dlog.h>
+#define DLOG(prio, fmt, arg...) \
+       do { SLOG(prio, LOG_TAG, fmt, ##arg); } while (0)
+#define INFO(fmt, arg...) SLOGI(fmt, ##arg)
+#define ERR(fmt, arg...) SLOGE("%s(%d): " fmt, __FUNCTION__, __LINE__, ##arg)
+#define DBG(fmt, arg...) SLOGD("%s:" fmt, __FUNCTION__, ##arg)
+#else //HELPER_DLOG_OUT
+#define PRT(prio, fmt, arg...) \
+       do { fprintf((prio?stderr:stdout),"[Contacts-svc-helper]" fmt"\n", ##arg); } while (0)
+#define INFO(fmt, arg...) PRT(0, fmt, ##arg)
+#define ERR(fmt, arg...) PRT(1,"%s(%d): " fmt, __FUNCTION__, __LINE__, ##arg)
+#define DBG(fmt, arg...) \
+       do { \
+               printf("\x1b[105;37m[Contacts-svc-helper]\x1b[0m(%s)" fmt "\n", __FUNCTION__, ##arg); \
+       } while (0)
+#endif //HELPER_DLOG_OUT
+
+#ifdef HELPER_DEBUGGING
+#define HELPER_FN_CALL DBG(">>>>>>>> called")
+#define HELPER_FN_END DBG("<<<<<<<< ended")
+#define HELPER_DBG(fmt, arg...) DBG("(%d) " fmt, __LINE__, ##arg)
+#else /* HELPER_DEBUGGING */
+#define HELPER_FN_CALL
+#define HELPER_FN_END
+#define HELPER_DBG(fmt, arg...)
+#endif /* HELPER_DEBUGGING */
+
+#define h_warn_if(expr, fmt, arg...) do { \
+       if (expr) { \
+               ERR(fmt, ##arg); \
+       } \
+} while (0)
+#define h_ret_if(expr) do { \
+       if (expr) { \
+               ERR("(%s)", #expr); \
+               return; \
+       } \
+} while (0)
+#define h_retv_if(expr, val) do { \
+       if (expr) { \
+               ERR("(%s)", #expr); \
+               return (val); \
+       } \
+} while (0)
+#define h_retm_if(expr, fmt, arg...) do { \
+       if (expr) { \
+               ERR(fmt, ##arg); \
+               return; \
+       } \
+} while (0)
+#define h_retvm_if(expr, val, fmt, arg...) do { \
+       if (expr) { \
+               ERR(fmt, ##arg); \
+               return (val); \
+       } \
+} while (0)
+
+#endif // __CTS_HELPER_INTERNAL_H__
+
diff --git a/helper/localize.c b/helper/localize.c
new file mode 100755 (executable)
index 0000000..b7be1f6
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *          Donghee Ye <donghee.ye@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "internal.h"
+#include "cts-normalize.h"
+#include "localize.h"
+
+/* korean -Hangul Jamo extended A*/
+#define CTS_JAMO_A_START (UChar)0xA960
+#define CTS_JAMO_A_END (UChar)0xA97F
+
+/* korean -Hangul Jamo extended B*/
+#define CTS_JAMO_B_START (UChar)0xD7B0
+#define CTS_JAMO_B_END (UChar)0xD7FF
+
+/* korean -Hangul Compatability */
+#define CTS_HAN_C_START (UChar)0x3130
+#define CTS_HAN_C_END (UChar)0x318F
+
+/* korean -Hangul halfwidth */
+#define CTS_HAN_HALF_START (UChar)0xFFA0
+#define CTS_HAN_HALF_END (UChar)0xFFDC
+
+static const char hangul_compatibility_choseong[] = {
+       0x31, 0x32, 0x34, 0x37, 0x38, 0x39, 0x40, 0x41,
+       0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+       0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x65, 0x66, 0x6E,
+       0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+       0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80,
+       0x81, 0x84, 0x85, 0x86, 0x00};
+static const unsigned char hangul_jamo_choseong[] = {
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x1A, 0x06, 0x07,           // to choseong 0x1100~0x115F
+       0x08, 0x21, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+       0x10, 0x11, 0x12, 0x14, 0x15, 0x1C, 0x1D, 0x1E, 0x20,
+       0x22, 0x23, 0x27, 0x29, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+       0x32, 0x36, 0x40, 0x47, 0x4C, 0x57, 0x58, 0x59, 0x00};
+
+static const char hangul_compatibility_jungseong[] = {
+       0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
+       0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E,
+       0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x87, 0x88,
+       0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x00};
+static const unsigned char hangul_jamo_jungseong[] = {
+       0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,   // to jungseong 0x1160~0x11A7
+       0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72,
+       0x73, 0x74, 0x75, 0x60, 0x84, 0x85, 0x88, 0x91, 0x92,
+       0x94, 0x9E, 0xA1, 0x00};
+
+static const char hangul_compatibility_jongseong[] = {
+       0x33, 0x35, 0x36, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E,
+       0x3F, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
+       0x6F, 0x70, 0x82, 0x83, 0x00};
+static const unsigned char hangul_jamo_jongseong[] = {
+       0xAA, 0xAC, 0xAD, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5,   // to jongseong 0x11A8~0x11FF
+       0xC7, 0xC8, 0xCC, 0xCE, 0xD3, 0xD7, 0xD9, 0xDF, 0xF1, 0xF2, 0x00};
+
+static inline bool is_hangul(UChar src)
+{
+       if ((0x1100 == (src & 0xFF00))       /* korean -Hangul Jamo*/
+                       || CTS_COMPARE_BETWEEN(CTS_JAMO_A_START, src, CTS_JAMO_A_END)
+                       || CTS_COMPARE_BETWEEN(CTS_JAMO_B_START, src, CTS_JAMO_B_END)
+                       || CTS_COMPARE_BETWEEN(CTS_HAN_C_START, src, CTS_HAN_C_END)
+                       || CTS_COMPARE_BETWEEN(CTS_HAN_HALF_START, src, CTS_HAN_HALF_END))
+               return true;
+       else
+               return FALSE;
+}
+
+static inline void hangul_compatibility2jamo(UChar *src)
+{
+       int unicode_value1 = 0;
+       int unicode_value2 = 0;
+
+       unicode_value1 = (0xFF00 & (*src)) >> 8;
+       unicode_value2 = (0xFF & (*src));
+
+       /* korean -Hangul Jamo halfwidth*/
+       if (CTS_COMPARE_BETWEEN(CTS_HAN_HALF_START, *src, CTS_HAN_HALF_END)) {
+               unicode_value1 = 0x31;
+
+               if (unicode_value2 < 0xBF)
+                       unicode_value2 -= 0x70;
+               else if (unicode_value2 < 0xC8)
+                       unicode_value2 -= 0x73;
+               else if (unicode_value2 < 0xD0)
+                       unicode_value2 -= 0x75;
+               else if (unicode_value2 < 0xD8)
+                       unicode_value2 -= 0x77;
+               else
+                       unicode_value2 -= 0x79;
+
+               (*src) = unicode_value1 << 8 | unicode_value2;
+       }
+
+       if (CTS_COMPARE_BETWEEN(CTS_HAN_C_START, *src, CTS_HAN_C_END))
+       {
+               char *pos;
+               if (NULL != (pos = strchr(hangul_compatibility_choseong, unicode_value2)))
+               {
+                       unicode_value1 = 0x11;
+                       unicode_value2 = hangul_jamo_choseong[pos - hangul_compatibility_choseong];
+                       (*src) = unicode_value1 << 8 | unicode_value2;
+               }
+               else if (NULL != (pos = strchr(hangul_compatibility_jungseong, unicode_value2)))
+               {
+                       unicode_value1 = 0x11;
+                       unicode_value2 = hangul_jamo_jungseong[pos - hangul_compatibility_jungseong];
+                       (*src) = unicode_value1 << 8 | unicode_value2;
+               }
+               else if (NULL != (pos = strchr(hangul_compatibility_jongseong, unicode_value2)))
+               {
+                       unicode_value1 = 0x11;
+                       unicode_value2 = hangul_jamo_jongseong[pos - hangul_compatibility_jongseong];
+                       (*src) = unicode_value1 << 8 | unicode_value2;
+               }
+       }
+}
+
+int helper_check_language(UChar *word)
+{
+       int type;
+
+       if (CTS_COMPARE_BETWEEN('0', word[0], '9')) {
+               type = CTS_LANG_NUMBER;
+       }
+       else if (CTS_COMPARE_BETWEEN(0x41, word[0], 0x7A)) {  /* english */
+               type = CTS_LANG_ENGLISH;
+       }
+       else if (is_hangul(word[0])){
+               type = CTS_LANG_KOREAN;
+       }
+       else
+               type = CTS_LANG_OTHERS;
+
+       return type;
+}
+
+void helper_extra_normalize(UChar *word, int32_t word_size)
+{
+       int i;
+       for (i=0;i<word_size;i++) {
+               if (is_hangul(word[i])) {
+                       hangul_compatibility2jamo(&word[i]);
+               }
+       }
+}
+
+int helper_get_language_type(const char *system_lang)
+{
+       int type;
+
+       h_retv_if(NULL == system_lang, CTS_LANG_OTHERS);
+
+       if (!strncmp(system_lang, "ko", sizeof("ko") - 1))
+               type = CTS_LANG_KOREAN;
+       else if (!strncmp(system_lang, "en", sizeof("en") - 1))
+               type = CTS_LANG_ENGLISH;
+       else
+               type = CTS_LANG_OTHERS;
+
+       return type;
+}
+
diff --git a/helper/localize.h b/helper/localize.h
new file mode 100755 (executable)
index 0000000..9bcef54
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *          Donghee Ye <donghee.ye@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_HELPER_LOCALIZE_H__
+#define __CTS_HELPER_LOCALIZE_H__
+
+#include <unicode/utypes.h>
+
+int helper_check_language(UChar *word);
+int helper_get_language_type(const char *system_lang);
+void helper_extra_normalize(UChar *word, int32_t word_size);
+
+#endif // __CTS_HELPER_LOCALIZE_H__
diff --git a/helper/main.c b/helper/main.c
new file mode 100755 (executable)
index 0000000..ec63e8b
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <glib.h>
+#include <string.h>
+#include <contacts-svc.h>
+
+#include "internal.h"
+#include "schema-recovery.h"
+#include "helper-socket.h"
+#include "utils.h"
+#include "sqlite.h"
+
+int main(int argc, char **argv)
+{
+       int ret;
+       GMainLoop *cts_helper_loop = NULL;
+
+       helper_check_schema();
+       if (2 <= argc && !strcmp(argv[1], "schema"))
+               return CTS_SUCCESS;
+
+       cts_helper_loop = g_main_loop_new (NULL, FALSE);
+       h_retvm_if(NULL == cts_helper_loop, CTS_ERR_FAIL, "g_main_loop_new() Failed");
+
+       ret = contacts_svc_connect();
+       h_retvm_if(CTS_SUCCESS != ret, ret, "contacts_svc_connect() Failed(%d)", ret);
+
+       helper_socket_init();
+       helper_init_configuration();
+
+       g_main_loop_run(cts_helper_loop);
+
+       helper_final_configuration();
+       ret = contacts_svc_disconnect();
+       h_retvm_if(CTS_SUCCESS != ret, ret, "contacts_svc_disconnect() Failed(%d)", ret);
+
+       g_main_loop_unref(cts_helper_loop);
+       return CTS_SUCCESS;
+}
diff --git a/helper/normalize.c b/helper/normalize.c
new file mode 100755 (executable)
index 0000000..241bbe8
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *          Donghee Ye <donghee.ye@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <string.h>
+#include <unicode/ustring.h>
+#include <unicode/unorm.h>
+#include <unicode/ucol.h>
+#include <contacts-svc.h>
+#include <vconf.h>
+#include <vconf-keys.h>
+
+#include "internal.h"
+#include "cts-sqlite.h"
+#include "localize.h"
+#include "normalize.h"
+#include "utils.h"
+
+#define array_sizeof(a) (sizeof(a) / sizeof(a[0]))
+
+int helper_unicode_to_utf8(char *src, int src_len, char *dest, int dest_size)
+{
+       int32_t size = 0;
+       UErrorCode status = 0;
+       UChar *unicode_src = (UChar *)src;
+
+       u_strToUTF8(dest, dest_size, &size, unicode_src, -1, &status);
+       h_retvm_if(U_FAILURE(status), CTS_ERR_ICU_FAILED,
+                       "u_strToUTF8() Failed(%s)", u_errorName(status));
+
+       dest[size]='\0';
+       return CTS_SUCCESS;
+}
+
+static inline int check_utf8(char c)
+{
+       if (c < 128)
+               return 1;
+       else if ((c & (char)0xe0) == (char)0xc0)
+               return 2;
+       else if ((c & (char)0xf0) == (char)0xe0)
+               return 3;
+       else if ((c & (char)0xf8) == (char)0xf0)
+               return 4;
+       else if ((c & (char)0xfc) == (char)0xf8)
+               return 5;
+       else if ((c & (char)0xfe) == (char)0xfc)
+               return 6;
+       else
+               return CTS_ERR_FAIL;
+}
+
+int helper_normalize_str(const char *src, char *dest, int dest_size)
+{
+       int type = CTS_LANG_OTHERS;
+       int32_t size;
+       UErrorCode status = 0;
+       UChar tmp_result[CTS_SQL_MAX_LEN];
+       UChar result[CTS_SQL_MAX_LEN];
+       int i = 0;
+       int j = 0;
+       int str_len = strlen(src);
+       int char_len = 0;
+
+       for (i=0;i<str_len;i+=char_len) {
+               char char_src[10];
+               char_len = check_utf8(src[i]);
+               memcpy(char_src, &src[i], char_len);
+               char_src[char_len] = '\0';
+
+               u_strFromUTF8(tmp_result, array_sizeof(tmp_result), NULL, char_src, -1, &status);
+               h_retvm_if(U_FAILURE(status), CTS_ERR_ICU_FAILED,
+                               "u_strFromUTF8() Failed(%s)", u_errorName(status));
+
+               u_strToLower(tmp_result, array_sizeof(tmp_result), tmp_result, -1, NULL, &status);
+               h_retvm_if(U_FAILURE(status), CTS_ERR_ICU_FAILED,
+                               "u_strToLower() Failed(%s)", u_errorName(status));
+
+               size = unorm_normalize(tmp_result, -1, UNORM_NFD, 0,
+                               (UChar *)result, array_sizeof(result), &status);
+               h_retvm_if(U_FAILURE(status), CTS_ERR_ICU_FAILED,
+                               "unorm_normalize(%s) Failed(%s)", char_src, u_errorName(status));
+
+               if (0 == i)
+                       type = helper_check_language(result);
+               helper_extra_normalize(result, size);
+
+               u_strToUTF8(&dest[j], dest_size-j, &size, result, -1, &status);
+               h_retvm_if(U_FAILURE(status), CTS_ERR_ICU_FAILED,
+                               "u_strToUTF8() Failed(%s)", u_errorName(status));
+               j += size;
+               dest[j++] = 0x01;
+       }
+       dest[j]='\0';
+       HELPER_DBG("src(%s) is transformed(%s)", src, dest);
+       return type;
+}
+
+int helper_collation_str(const char *src, char *dest, int dest_size)
+{
+       HELPER_FN_CALL;
+       int32_t size = 0;
+       UErrorCode status = 0;
+       UChar tmp_result[CTS_SQL_MAX_LEN];
+       UCollator *collator;
+       const char *region;
+
+       region = vconf_get_str(VCONFKEY_REGIONFORMAT);
+       HELPER_DBG("region %s", region);
+       collator = ucol_open(region, &status);
+       h_retvm_if(U_FAILURE(status), CTS_ERR_ICU_FAILED,
+                       "ucol_open() Failed(%s)", u_errorName(status));
+
+       if (U_FAILURE(status)){
+               ERR("ucol_setAttribute Failed(%s)", u_errorName(status));
+               ucol_close(collator);
+               return CTS_ERR_ICU_FAILED;
+       }
+
+       u_strFromUTF8(tmp_result, array_sizeof(tmp_result), NULL, src, -1, &status);
+       if (U_FAILURE(status)){
+               ERR("u_strFromUTF8 Failed(%s)", u_errorName(status));
+               ucol_close(collator);
+               return CTS_ERR_ICU_FAILED;
+       }
+       size = ucol_getSortKey(collator, tmp_result, -1, (uint8_t *)dest, dest_size);
+       ucol_close(collator);
+       dest[size]='\0';
+
+       return CTS_SUCCESS;
+}
+
+API int cts_helper_normalize_name(char dest[][CTS_SQL_MAX_LEN])
+{
+       int lang_type=0;
+       int ret=CTS_ERR_NO_DATA;
+       int sizes[CTS_NN_MAX]={0};
+       char normalized_first[CTS_SQL_MAX_LEN];
+       char normalized_last[CTS_SQL_MAX_LEN];
+
+       sizes[CTS_NN_FIRST] = strlen(dest[CTS_NN_FIRST]);
+       sizes[CTS_NN_LAST] = strlen(dest[CTS_NN_LAST]);
+
+       if (sizes[CTS_NN_FIRST]) {
+               ret = helper_normalize_str(dest[CTS_NN_FIRST], normalized_first,
+                               sizeof(normalized_first));
+               h_retvm_if(ret < CTS_SUCCESS, ret, "helper_normalize_str() Failed(%d)", ret);
+               lang_type = ret;
+
+               sizes[CTS_NN_FIRST] = strlen(normalized_first);
+       }
+
+       if (sizes[CTS_NN_LAST]) {
+               ret = helper_normalize_str(dest[CTS_NN_LAST], normalized_last,
+                               sizeof(normalized_first));
+               h_retvm_if(ret < CTS_SUCCESS, ret, "helper_normalize_str() Failed(%d)", ret);
+               if (lang_type < ret) lang_type = ret;
+
+               sizes[CTS_NN_LAST] = strlen(normalized_last);
+       }
+
+       if (sizes[CTS_NN_FIRST])
+               snprintf(dest[CTS_NN_FIRST], sizeof(dest[CTS_NN_FIRST]), "%s", normalized_first);
+       if (sizes[CTS_NN_LAST])
+               snprintf(dest[CTS_NN_LAST], sizeof(dest[CTS_NN_LAST]), "%s", normalized_last);
+
+       return lang_type;
+}
+
diff --git a/helper/normalize.h b/helper/normalize.h
new file mode 100755 (executable)
index 0000000..666c11f
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *          Donghee Ye <donghee.ye@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_HELPER_NORMALIZE_H__
+#define __CTS_HELPER_NORMALIZE_H__
+
+#include "cts-normalize.h"
+
+int helper_normalize_str(const char *src, char *dest, int dest_size);
+int helper_collation_str(const char *src, char *dest, int dest_size);
+int helper_unicode_to_utf8(char *src, int src_len, char *dest, int dest_size);
+
+#endif // __CTS_HELPER_NORMALIZE_H__
+
diff --git a/helper/schema-recovery.c b/helper/schema-recovery.c
new file mode 100755 (executable)
index 0000000..851aa24
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <db-util.h>
+#include <sqlite3.h>
+#include <contacts-svc.h>
+
+#include "internal.h"
+#include "sqlite.h"
+#include "schema.h"
+#include "schema-recovery.h"
+#include "cts-schema.h"
+
+static inline int helper_check_db_file(void)
+{
+       int fd = open(CTS_DB_PATH, O_RDONLY);
+       h_retvm_if(-1 == fd, CTS_ERR_NO_DB_FILE,
+                       "DB file(%s) is not exist", CTS_DB_PATH);
+
+       close(fd);
+       return CTS_SUCCESS;
+}
+
+static inline int remake_db_file()
+{
+       int ret, fd;
+       char *errmsg;
+       sqlite3 *db;
+
+       ret = helper_db_open(&db);
+       h_retvm_if(CTS_SUCCESS != ret, ret, "helper_db_open() Failed(%d)", ret);
+
+       ret = sqlite3_exec(db, schema_query, NULL, 0, &errmsg);
+       if (SQLITE_OK != ret) {
+               ERR("remake contacts DB file is Failed : %s", errmsg);
+               sqlite3_free(errmsg);
+       }
+
+       helper_db_close();
+
+       fd = open(CTS_DB_PATH, O_CREAT | O_RDWR, 0660);
+       h_retvm_if(-1 == fd, CTS_ERR_FAIL, "open Failed");
+
+       fchown(fd, getuid(), CTS_SECURITY_FILE_GROUP);
+       fchmod(fd, CTS_SECURITY_DEFAULT_PERMISSION);
+       close(fd);
+
+       fd = open(CTS_DB_JOURNAL_PATH, O_CREAT | O_RDWR, 0660);
+       h_retvm_if(-1 == fd, CTS_ERR_FAIL, "open Failed");
+
+       fchown(fd, getuid(), CTS_SECURITY_FILE_GROUP);
+       fchmod(fd, CTS_SECURITY_DEFAULT_PERMISSION);
+       close(fd);
+
+       return CTS_SUCCESS;
+}
+
+int helper_check_schema(void)
+{
+       if (CTS_ERR_NO_DB_FILE == helper_check_db_file())
+               remake_db_file();
+
+       return CTS_SUCCESS;
+}
+
diff --git a/helper/schema-recovery.h b/helper/schema-recovery.h
new file mode 100755 (executable)
index 0000000..9f7a2f8
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_HELPER_SCHEMA_RECOVERY_H__
+#define __CTS_HELPER_SCHEMA_RECOVERY_H__
+
+int helper_check_schema();
+
+#endif // __CTS_HELPER_SCHEMA_RECOVERY_H__
+
+
diff --git a/helper/sim.c b/helper/sim.c
new file mode 100755 (executable)
index 0000000..13d9bb1
--- /dev/null
@@ -0,0 +1,617 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <string.h>
+#include <TapiCommon.h>
+#include <ITapiSim.h>
+#include <contacts-svc.h>
+
+#include "cts-addressbook.h"
+#include "helper-socket.h"
+#include "internal.h"
+#include "normalize.h"
+#include "sqlite.h"
+#include "utils.h"
+#include "sim.h"
+
+#define CTS_SIM_EVENT_NUM 2
+#define CTS_TAPI_SIM_PB_MAX 0xFFFF
+#define CTS_MIN(a, b) (a>b)?b:a
+
+static int helper_sim_read_record_cb(const TelTapiEvent_t *pdata, void *data);
+static int helper_sim_pb_count_cb(const TelTapiEvent_t *pdata, void *data);
+
+static TelSimImsiInfo_t TAPI_imsi;
+static void *helper_import_sim_data = NULL;
+
+static unsigned int TAPI_SIM_EVENT_ID[CTS_SIM_EVENT_NUM];
+static const int TAPI_SIM_EVENT[CTS_SIM_EVENT_NUM] =
+{
+       TAPI_EVENT_SIM_PB_ACCESS_READ_CNF,
+       TAPI_EVENT_SIM_PB_STORAGE_COUNT_CNF
+};
+static const TelAppCallback TAPI_SIM_EVENT_CB[CTS_SIM_EVENT_NUM] =
+{
+       helper_sim_read_record_cb,
+       helper_sim_pb_count_cb
+};
+
+static int helper_register_tapi_cnt = 0;
+static int helper_register_tapi_sim_event(void)
+{
+       int i, ret;
+
+       if (0 == helper_register_tapi_cnt)
+       {
+               ret = tel_init();
+               h_retvm_if(TAPI_API_SUCCESS != ret, CTS_ERR_TAPI_FAILED,
+                               "tel_init() is Failed(%d)", ret);
+
+               ret = tel_register_app_name(CTS_DBUS_SERVICE);
+               h_retvm_if(TAPI_API_SUCCESS != ret, CTS_ERR_TAPI_FAILED,
+                               "tel_register_app_name(%s) is Failed(%d)", CTS_DBUS_SERVICE, ret);
+
+               for (i=0;i<CTS_SIM_EVENT_NUM;i++)
+               {
+                       ret = tel_register_event(TAPI_SIM_EVENT[i], &TAPI_SIM_EVENT_ID[i],
+                                       TAPI_SIM_EVENT_CB[i], NULL);
+                       h_retvm_if(TAPI_API_SUCCESS != ret, CTS_ERR_TAPI_FAILED,
+                                       "tel_register_event(Event[%d]) is Failed(%d)", i, ret);
+               }
+       }
+       helper_register_tapi_cnt++;
+
+       return CTS_SUCCESS;
+}
+
+static int helper_deregister_tapi_sim_event(void)
+{
+       int ret, i;
+
+       if (1 == helper_register_tapi_cnt)
+       {
+               for (i=0;i<CTS_SIM_EVENT_NUM;i++)
+               {
+                       ret = tel_deregister_event(TAPI_SIM_EVENT_ID[i]);
+                       h_warn_if(TAPI_API_SUCCESS != ret,
+                                       "tel_register_event(Event[%d]) is Failed(%d)", i, ret);
+               }
+
+               ret = tel_deinit();
+               h_retvm_if(TAPI_API_SUCCESS != ret, CTS_ERR_TAPI_FAILED,
+                               "tel_deinti() Failed(%d)", ret);
+       }
+       helper_register_tapi_cnt--;
+
+       return CTS_SUCCESS;
+}
+
+unsigned short HELPER_GSM7BitTable[128] = {
+       0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
+       0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
+       0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
+       0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
+       0x0020, 0x0021, 0x0022, 0x0023, 0x00A4, 0x0025, 0x0026, 0x0027,
+       0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+       0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+       0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+       0x00A1, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+       0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+       0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+       0x0058, 0x0059, 0x005A, 0x00C4, 0x00D6, 0x00D1, 0x00DC, 0x00A7,
+       0x00BF, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+       0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+       0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+       0x0078, 0x0079, 0x007A, 0x00E4, 0x00F6, 0x00F1, 0x00FC, 0x00E0
+};
+
+static int helper_sim_data_to_utf8(TelSimTextEncrypt_t type,
+               char *src, int src_len, char *dest, int dest_size)
+{
+       h_retvm_if(0 == src_len || NULL == src, CTS_ERR_ARG_INVALID,
+                       "src(%p, len=%d) is invalid", src, src_len);
+       h_retvm_if(0 == dest_size || NULL == dest, CTS_ERR_ARG_INVALID,
+                       "dest(%p, len=%d) is invalid", dest, dest_size);
+
+       switch (type)
+       {
+       case TAPI_SIM_TEXT_ENC_GSM7BIT:
+       case TAPI_SIM_TEXT_ENC_ASCII:
+               memcpy(dest, src, CTS_MIN(dest_size, src_len));
+               dest[CTS_MIN(dest_size-1, src_len)] = '\0';
+               break;
+       case TAPI_SIM_TEXT_ENC_UCS2:
+       case TAPI_SIM_TEXT_ENC_HEX:
+               return helper_unicode_to_utf8(src, src_len, dest, dest_size);
+       default:
+               ERR("Unknown Encryption Type(%d)", type);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       return CTS_SUCCESS;
+}
+
+#define HELPER_SIM_DATA_MAX_LENGTH 1024
+
+static int helper_insert_SDN(TelSimPb2GData_t *pb2g_data)
+{
+       int ret;
+       char utf_data[HELPER_SIM_DATA_MAX_LENGTH];
+
+       ret = helper_sim_data_to_utf8(pb2g_data->NameEncryptType, (char *)pb2g_data->Name,
+                       CTS_MIN(sizeof(pb2g_data->Name), pb2g_data->NameLen),
+                       utf_data, sizeof(utf_data));
+       h_retvm_if(ret != CTS_SUCCESS, ret, "helper_sim_data_to_utf8 is Failed(%d)", ret);
+
+       ret = helper_insert_SDN_contact(utf_data, (char *)pb2g_data->Number);
+       h_retvm_if(ret != CTS_SUCCESS, ret, "helper_insert_SDN_contact() Failed(%d)", ret);
+
+       return ret;
+}
+
+static int helper_insert_2g_contact(int index, TelSimPb2GData_t *pb2g_data)
+{
+       int ret, found_id;
+       char uid[32];
+       char utf_data[HELPER_SIM_DATA_MAX_LENGTH];
+       CTSstruct *contact;
+       GSList *numbers=NULL;
+       CTSvalue *name_val, *number_val, *base;
+
+       h_retvm_if(index <= 0, CTS_ERR_ARG_INVALID, "The index(%d) is invalid", index);
+
+       snprintf(uid, sizeof(uid), "SIM:%s-%s-%s-%d",
+                       TAPI_imsi.szMcc, TAPI_imsi.szMnc, TAPI_imsi.szMsin, index);
+       HELPER_DBG("UID = %s", uid);
+
+       found_id = contacts_svc_find_contact_by(CTS_FIND_BY_UID, uid);
+
+       ret = helper_sim_data_to_utf8(pb2g_data->NameEncryptType, (char *)pb2g_data->Name,
+                       CTS_MIN(sizeof(pb2g_data->Name), pb2g_data->NameLen),
+                       utf_data, sizeof(utf_data));
+       h_retvm_if(ret != CTS_SUCCESS, ret, "helper_sim_data_to_utf8 is Failed(%d)", ret);
+
+       contact = contacts_svc_struct_new(CTS_STRUCT_CONTACT);
+
+       base = contacts_svc_value_new(CTS_VALUE_CONTACT_BASE_INFO);
+       if (base) {
+               contacts_svc_value_set_str(base, CTS_BASE_VAL_UID_STR, uid);
+               contacts_svc_struct_store_value(contact, CTS_CF_BASE_INFO_VALUE, base);
+               contacts_svc_value_free(base);
+       }
+
+       name_val = contacts_svc_value_new(CTS_VALUE_NAME);
+       if (name_val) {
+               contacts_svc_value_set_str(name_val, CTS_NAME_VAL_DISPLAY_STR, utf_data);
+               contacts_svc_struct_store_value(contact, CTS_CF_NAME_VALUE, name_val);
+               contacts_svc_value_free(name_val);
+       }
+
+       number_val = contacts_svc_value_new(CTS_VALUE_NUMBER);
+       if (number_val) {
+               contacts_svc_value_set_str(number_val, CTS_NUM_VAL_NUMBER_STR,
+                               (char *)pb2g_data->Number);
+               contacts_svc_value_set_int(number_val, CTS_NUM_VAL_TYPE_INT, CTS_NUM_TYPE_CELL);
+               contacts_svc_value_set_bool(number_val, CTS_NUM_VAL_DEFAULT_BOOL, true);
+       }
+       numbers = g_slist_append(numbers, number_val);
+
+       contacts_svc_struct_store_list(contact, CTS_CF_NUMBER_LIST, numbers);
+       contacts_svc_value_free(number_val);
+       g_slist_free(numbers);
+
+       if (0 < found_id) {
+               CTSstruct *temp;
+               ret = contacts_svc_get_contact(found_id, &temp);
+               if (CTS_SUCCESS == ret) {
+                       contacts_svc_struct_merge(temp, contact);
+                       contacts_svc_struct_free(contact);
+                       contact = temp;
+                       ret = contacts_svc_update_contact(contact);
+                       h_warn_if(ret < CTS_SUCCESS, "contacts_svc_update_contact() Failed(%d)", ret);
+               } else {
+                       ERR("contacts_svc_get_contact() Failed(%d)", ret);
+               }
+       } else {
+               ret = contacts_svc_insert_contact(CTS_ADDRESSBOOK_INTERNAL, contact);
+               h_warn_if(ret < CTS_SUCCESS, "contacts_svc_insert_contact() Failed(%d)", ret);
+       }
+       contacts_svc_struct_free(contact);
+
+       return ret;
+}
+
+static int helper_insert_3g_contact(int index, TelSimPb3GData_t *pb3g_data)
+{
+       int i, ret, found_id;
+       char uid[32];
+       char utf_data[HELPER_SIM_DATA_MAX_LENGTH];
+       CTSstruct *contact;
+       CTSvalue *name_val=NULL, *number_val, *email_val, *base;
+       TelSimPb3GFileDataInfo_t temp;
+       GSList *numbers=NULL, *emails=NULL;
+
+       h_retvm_if(index <= 0, CTS_ERR_ARG_INVALID, "The index(%d) is invalid", index);
+
+       snprintf(uid, sizeof(uid), "SIM:%s-%s-%s-%d",
+                       TAPI_imsi.szMcc, TAPI_imsi.szMnc, TAPI_imsi.szMsin, index);
+       HELPER_DBG("UID = %s", uid);
+       found_id = contacts_svc_find_contact_by(CTS_FIND_BY_UID, uid);
+
+       contact = contacts_svc_struct_new(CTS_STRUCT_CONTACT);
+
+       base = contacts_svc_value_new(CTS_VALUE_CONTACT_BASE_INFO);
+       if (base) {
+               contacts_svc_value_set_str(base, CTS_BASE_VAL_UID_STR, uid);
+               contacts_svc_struct_store_value(contact, CTS_CF_BASE_INFO_VALUE, base);
+               contacts_svc_value_free(base);
+       }
+
+       for (i=0;i<pb3g_data->FileTypeCount;i++)
+       {
+               temp = pb3g_data->PbFileDataInfo[i];
+               switch (temp.FileType)
+               {
+               case TAPI_PB_3G_NAME:
+               case TAPI_PB_3G_SNE:
+                       ret = helper_sim_data_to_utf8(temp.FileDataType.EncryptionType,
+                                       (char *)temp.FileData,
+                                       CTS_MIN(sizeof(temp.FileData), temp.FileDataLength),
+                                       utf_data, sizeof(utf_data));
+                       if (ret != CTS_SUCCESS) {
+                               ERR("helper_sim_data_to_utf8() Failed(%d)", ret);
+                               goto CONVERT_3GPB_FAIL;
+                       }
+
+                       if (!name_val)
+                               name_val = contacts_svc_value_new(CTS_VALUE_NAME);
+                       if (name_val) {
+                               if (TAPI_PB_3G_NAME == temp.FileType)
+                                       contacts_svc_value_set_str(name_val, CTS_NAME_VAL_FIRST_STR, utf_data);
+                               else
+                                       contacts_svc_value_set_str(name_val, CTS_NAME_VAL_LAST_STR, utf_data);
+                       }
+
+                       contacts_svc_struct_store_value(contact, CTS_CF_NAME_VALUE, name_val);
+                       break;
+               case TAPI_PB_3G_NUMBER:
+               case TAPI_PB_3G_ANR:
+               case TAPI_PB_3G_ANRA:
+               case TAPI_PB_3G_ANRB:
+                       number_val = contacts_svc_value_new(CTS_VALUE_NUMBER);
+                       if (number_val) {
+                               contacts_svc_value_set_str(number_val, CTS_NUM_VAL_NUMBER_STR,
+                                               (char *)temp.FileData);
+                               //contacts_svc_value_set_int(number_val, CTS_NUM_VAL_TYPE_INT, CTS_NUM_TYPE_CELL);
+                               if (TAPI_PB_3G_NUMBER == temp.FileType)
+                                       contacts_svc_value_set_bool(number_val, CTS_NUM_VAL_DEFAULT_BOOL, true);
+                       }
+                       numbers = g_slist_append(numbers, number_val);
+                       contacts_svc_struct_store_list(contact, CTS_CF_NUMBER_LIST, numbers);
+                       contacts_svc_value_free(number_val);
+                       break;
+               case TAPI_PB_3G_EMAIL:
+                       ret = helper_sim_data_to_utf8(temp.FileDataType.EncryptionType,
+                                       (char *)temp.FileData,
+                                       CTS_MIN(sizeof(temp.FileData), temp.FileDataLength),
+                                       utf_data, sizeof(utf_data));
+                       if (ret != CTS_SUCCESS) {
+                               ERR("helper_sim_data_to_utf8() Failed(%d)", ret);
+                               goto CONVERT_3GPB_FAIL;
+                       }
+
+                       email_val = contacts_svc_value_new(CTS_VALUE_EMAIL);
+                       if (email_val) {
+                               contacts_svc_value_set_str(email_val, CTS_EMAIL_VAL_ADDR_STR,
+                                               (char *)temp.FileData);
+                               contacts_svc_value_set_bool(email_val, CTS_NUM_VAL_DEFAULT_BOOL, true);
+                       }
+                       emails = g_slist_append(emails, email_val);
+                       contacts_svc_struct_store_list(contact, CTS_CF_EMAIL_LIST, emails);
+                       contacts_svc_value_free(email_val);
+                       break;
+               default:
+                       ERR("Unknown file type=%d", temp.FileType);
+                       break;
+               }
+       }
+
+       if (0 < found_id) {
+               CTSstruct *temp;
+               ret = contacts_svc_get_contact(found_id, &temp);
+               if (CTS_SUCCESS == ret) {
+                       contacts_svc_struct_merge(temp, contact);
+                       contacts_svc_struct_free(contact);
+                       contact = temp;
+                       ret = contacts_svc_update_contact(contact);
+                       h_warn_if(ret < CTS_SUCCESS, "contacts_svc_update_contact() Failed(%d)", ret);
+               } else {
+                       ERR("contacts_svc_get_contact() Failed(%d)", ret);
+               }
+       } else {
+               ret = contacts_svc_insert_contact(CTS_ADDRESSBOOK_INTERNAL, contact);
+               h_warn_if(ret < CTS_SUCCESS, "contacts_svc_insert_contact() Failed(%d)", ret);
+       }
+
+CONVERT_3GPB_FAIL:
+       contacts_svc_struct_free(contact);
+       return ret;
+}
+
+static int helper_sim_read_record_cb(const TelTapiEvent_t *sim_event, void *data)
+{
+       int ret, saved_pb_num, i=0, req_id;
+       TelSimPbRecordData_t *sim_info;
+
+       HELPER_FN_CALL;
+
+       h_retvm_if(TAPI_EVENT_CLASS_SIM != sim_event->EventClass ||
+                       TAPI_EVENT_SIM_PB_ACCESS_READ_CNF != sim_event->EventType,
+                       CTS_ERR_TAPI_FAILED,
+                       "Unknown Event(EventClass = 0x%X, EventType = 0x%X",
+                       sim_event->EventClass, sim_event->EventType);
+
+       sim_info = (TelSimPbRecordData_t*)sim_event->pData;
+       if (NULL == sim_info) {
+               ERR("sim_info is NULL, Status = %d", sim_event->Status);
+               goto ERROR_RETURN;
+       }
+
+       if (TAPI_SIM_PB_SUCCESS != sim_event->Status) {
+               if (TAPI_SIM_PB_SDN == sim_info->StorageFileType &&
+                               TAPI_SIM_PB_INVALID_INDEX == sim_event->Status)
+               {
+                       HELPER_DBG("Index = %d", sim_info->Index);
+                       ret = tel_read_sim_pb_record(sim_info->StorageFileType,
+                                       sim_info->Index+1, &req_id);
+                       if (TAPI_API_SUCCESS != ret) {
+                               ERR("tel_read_sim_pb_record() Failed(%d)", ret);
+                               goto ERROR_RETURN;
+                       }
+                       return CTS_SUCCESS;
+               }
+               ERR("SIM phonebook access Failed(%d)", sim_event->Status);
+               goto ERROR_RETURN;
+       }
+
+       switch (sim_info->StorageFileType)
+       {
+       case TAPI_SIM_PB_SDN:
+               saved_pb_num = sim_event->pDataLen / sizeof(TelSimPbRecordData_t);
+               if (saved_pb_num <= 0 || TAPI_SIM_3G_PB_MAX_RECORD_COUNT < saved_pb_num) {
+                       ERR("received saved_pb_num is invalid(%d)", saved_pb_num);
+                       goto ERROR_RETURN;
+               }
+               while (true) {
+                       ret = helper_insert_SDN(&sim_info->ContactInfo.Pb2GData);
+                       h_warn_if(ret < CTS_SUCCESS, "helper_insert_SDN() is Failed(%d)", ret);
+                       if (saved_pb_num == ++i) break;
+                       sim_info++;
+               }
+               //sim_info->NextIndex = sim_info->Index+1;
+               break;
+       case TAPI_SIM_PB_ADN:
+               saved_pb_num = sim_event->pDataLen / sizeof(TelSimPbRecordData_t);
+               if (saved_pb_num <= 0 || TAPI_SIM_3G_PB_MAX_RECORD_COUNT < saved_pb_num) {
+                       ERR("received saved_pb_num is invalid(%d)", saved_pb_num);
+                       goto ERROR_RETURN;
+               }
+               while (true) {
+                       ret = helper_insert_2g_contact(sim_info->Index, &sim_info->ContactInfo.Pb2GData);
+                       h_warn_if(ret < CTS_SUCCESS, "helper_insert_2g_contact() is Failed(%d)", ret);
+                       if (saved_pb_num == ++i) break;
+                       sim_info++;
+               }
+               break;
+       case TAPI_SIM_PB_3GSIM:
+               saved_pb_num = sim_event->pDataLen / sizeof(TelSimPbRecordData_t);
+               HELPER_DBG("saved_pb_num = %d", saved_pb_num);
+               if (saved_pb_num <= 0 || TAPI_SIM_3G_PB_MAX_RECORD_COUNT < saved_pb_num) {
+                       ERR("received saved_pb_num is invalid(%d)", saved_pb_num);
+                       goto ERROR_RETURN;
+               }
+               while (true) {
+                       ret = helper_insert_3g_contact(sim_info->Index, &sim_info->ContactInfo.Pb3GData);
+                       h_warn_if(ret < CTS_SUCCESS, "helper_insert_3g_contact() is Failed(%d)", ret);
+                       if (saved_pb_num == ++i) break;
+                       sim_info++;
+               }
+               break;
+       case TAPI_SIM_PB_FDN:
+       case TAPI_SIM_PB_MSISDN:
+       default:
+               ERR("Unknown storage type(%d)", sim_info->StorageFileType);
+               goto ERROR_RETURN;
+       }
+       if (sim_info->NextIndex && CTS_TAPI_SIM_PB_MAX != sim_info->NextIndex) {
+               HELPER_DBG("NextIndex = %d", sim_info->NextIndex);
+               ret = tel_read_sim_pb_record(sim_info->StorageFileType,
+                               sim_info->NextIndex, &req_id);
+               if (TAPI_API_SUCCESS != ret) {
+                       ERR("tel_read_sim_pb_record() Failed(%d)", ret);
+                       goto ERROR_RETURN;
+               }
+       }
+       else {
+               contacts_svc_end_trans(true);
+               if (helper_import_sim_data) {
+                       ret = helper_socket_return(helper_import_sim_data, CTS_SUCCESS, 0, NULL);
+                       h_warn_if(CTS_SUCCESS != ret, "helper_socket_return() Failed(%d)", ret);
+                       helper_import_sim_data = NULL;
+                       memset(&TAPI_imsi, 0x00, sizeof(TelSimImsiInfo_t));
+               }
+
+               helper_deregister_tapi_sim_event();
+               helper_trim_memory();
+       }
+       return CTS_SUCCESS;
+ERROR_RETURN:
+       contacts_svc_end_trans(false);
+       if (helper_import_sim_data) {
+               ret = helper_socket_return(helper_import_sim_data, CTS_SUCCESS, 0, NULL);
+               h_warn_if(CTS_SUCCESS != ret, "helper_socket_return() Failed(%d)", ret);
+               helper_import_sim_data = NULL;
+               memset(&TAPI_imsi, 0x00, sizeof(TelSimImsiInfo_t));
+       }
+       helper_deregister_tapi_sim_event();
+       helper_trim_memory();
+       return CTS_ERR_TAPI_FAILED;
+}
+
+int helper_sim_read_pb_record(void *data)
+{
+       int ret, req_id;
+       TelSimPbFileType_t storage;
+       TelSimCardType_t cardInfo;
+
+       h_retvm_if(NULL != helper_import_sim_data, CTS_ERR_ENV_INVALID,
+                       "Helper is already processing with sim");
+
+       ret = helper_register_tapi_sim_event();
+       h_retvm_if(TAPI_API_SUCCESS != ret, ret,
+                       "helper_register_tapi_sim_event() Failed(%d)", ret);
+
+       ret = tel_get_sim_type(&cardInfo);
+       h_retvm_if(TAPI_API_SUCCESS != ret, CTS_ERR_TAPI_FAILED,
+                       "tel_get_sim_type() Failed(%d)", ret);
+
+       if (TAPI_SIM_CARD_TYPE_USIM == cardInfo)
+               storage = TAPI_SIM_PB_3GSIM;
+       else
+               storage = TAPI_SIM_PB_ADN;
+
+       int first_id, sim_pb_inited;
+       TelSimPbList_t pb_list = {0};
+
+       ret = tel_get_sim_pb_init_info(&sim_pb_inited, &pb_list, &first_id);
+       h_retvm_if(TAPI_API_SUCCESS != ret, CTS_ERR_TAPI_FAILED,
+                       "tel_get_sim_pb_init_info() Failed(%d)", ret);
+       HELPER_DBG("sim_pb_inited(%d), first_id(%d)", sim_pb_inited, first_id);
+
+       tel_get_sim_imsi(&TAPI_imsi);
+       h_retvm_if(CTS_SUCCESS != ret, ret, "tel_get_sim_imsi() Failed(%d)", ret);
+
+       if (sim_pb_inited) {
+               if (CTS_TAPI_SIM_PB_MAX == first_id) return CTS_ERR_NO_DATA;
+               ret = tel_read_sim_pb_record(storage, first_id, &req_id);
+               h_retvm_if(TAPI_API_SUCCESS != ret, CTS_ERR_TAPI_FAILED,
+                               "tel_read_sim_pb_record() Failed(%d)", ret);
+       }
+
+       ret = contacts_svc_begin_trans();
+       h_retvm_if(CTS_SUCCESS != ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       helper_import_sim_data = data;
+
+       return CTS_SUCCESS;
+}
+
+
+static int helper_sim_pb_count_cb(const TelTapiEvent_t *sim_event, void *data)
+{
+       int ret, req_id;
+       TelSimPbStorageInfo_t *sim_info;
+
+       HELPER_FN_CALL;
+
+       h_retvm_if(TAPI_EVENT_CLASS_SIM != sim_event->EventClass ||
+                       TAPI_EVENT_SIM_PB_STORAGE_COUNT_CNF != sim_event->EventType,
+                       CTS_ERR_TAPI_FAILED,
+                       "Unknown Event(EventClass = 0x%X, EventType = 0x%X",
+                       sim_event->EventClass, sim_event->EventType);
+
+       sim_info = (TelSimPbStorageInfo_t *)sim_event->pData;
+       if (NULL == sim_info) {
+               ERR("sim_info is NULL, Status = %d", sim_event->Status);
+               goto ERROR_RETURN;
+       }
+
+       if (TAPI_SIM_PB_SUCCESS != sim_event->Status) {
+               ERR("SIM phonebook access Failed(%d)", sim_event->Status);
+               goto ERROR_RETURN;
+       }
+
+       switch (sim_info->StorageFileType)
+       {
+       case TAPI_SIM_PB_SDN:
+               if (sim_info->UsedRecordCount) {
+                       ret = tel_read_sim_pb_record(TAPI_SIM_PB_SDN, 1, &req_id);
+                       h_retvm_if(TAPI_API_SUCCESS != ret, CTS_ERR_TAPI_FAILED,
+                                       "tel_read_sim_pb_record() Failed(%d)", ret);
+               }
+               break;
+       case TAPI_SIM_PB_ADN:
+       case TAPI_SIM_PB_3GSIM:
+       case TAPI_SIM_PB_FDN:
+       case TAPI_SIM_PB_MSISDN:
+       default:
+               ERR("Unknown storage type(%d)", sim_info->StorageFileType);
+               goto ERROR_RETURN;
+       }
+
+       return CTS_SUCCESS;
+
+ERROR_RETURN:
+       helper_deregister_tapi_sim_event();
+       return CTS_ERR_TAPI_FAILED;
+}
+
+int helper_sim_read_SDN(void* data)
+{
+       int ret, req_id, card_changed=0;
+       TelSimCardStatus_t sim_status;
+
+       HELPER_FN_CALL;
+
+       h_retvm_if(NULL != helper_import_sim_data, CTS_ERR_ENV_INVALID,
+                       "Helper is already processing with sim");
+
+       ret = helper_register_tapi_sim_event();
+       h_retvm_if(TAPI_API_SUCCESS != ret, ret,
+                       "helper_register_tapi_sim_event() Failed(%d)", ret);
+
+       ret = tel_get_sim_init_info(&sim_status, &card_changed);
+       h_retvm_if(TAPI_API_SUCCESS != ret, CTS_ERR_TAPI_FAILED,
+                       "tel_get_sim_init_info() Failed(%d)", ret);
+       HELPER_DBG("sim_status = %d, card_changed = %d", sim_status, card_changed);
+
+       if (TAPI_SIM_STATUS_CARD_NOT_PRESENT == sim_status ||
+                       TAPI_SIM_STATUS_CARD_REMOVED == sim_status)
+       {
+               ret = helper_delete_SDN_contact();
+               h_retvm_if(CTS_SUCCESS != ret, ret, "helper_delete_SDN_contact() Failed(%d)", ret);
+       }
+       else if (TAPI_SIM_STATUS_SIM_INIT_COMPLETED == sim_status)
+       {
+               ret = helper_delete_SDN_contact();
+               h_retvm_if(CTS_SUCCESS != ret, ret, "helper_delete_SDN_contact() Failed(%d)", ret);
+
+               ret = tel_get_sim_pb_count(TAPI_SIM_PB_SDN, &req_id);
+               h_retvm_if(TAPI_API_SUCCESS != ret, CTS_ERR_TAPI_FAILED,
+                               "tel_get_sim_pb_count() Failed(%d)", ret);
+
+               //ret = contacts_svc_begin_trans();
+               //h_retvm_if(CTS_SUCCESS != ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+               helper_import_sim_data = data;
+       }
+
+       return CTS_SUCCESS;
+}
diff --git a/helper/sim.h b/helper/sim.h
new file mode 100755 (executable)
index 0000000..8b3c769
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_HELPER_SIM_H__
+#define __CTS_HELPER_SIM_H__
+
+int helper_sim_read_pb_record(void* data);
+int helper_sim_read_SDN(void* data);
+
+
+#endif // __CTS_HELPER_SIM_H__
+
diff --git a/helper/sqlite.c b/helper/sqlite.c
new file mode 100755 (executable)
index 0000000..63bccc5
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <unistd.h>
+#include <string.h>
+#include <db-util.h>
+#include <fcntl.h>
+
+#include "cts-errors.h"
+#include "cts-schema.h"
+#include "cts-sqlite.h"
+#include "cts-utils.h"
+
+#include "internal.h"
+#include "normalize.h"
+#include "utils.h"
+
+static sqlite3 *helper_db;
+
+int helper_db_open(sqlite3 **db)
+{
+       HELPER_FN_CALL;
+       int ret;
+
+       if (!helper_db)
+       {
+               ret = db_util_open(CTS_DB_PATH, &helper_db, 0);
+               h_retvm_if(ret != SQLITE_OK, CTS_ERR_DB_NOT_OPENED,
+                               "db_util_open() Failed(%d)", ret);
+       }
+       if (db)
+               *db = helper_db;
+       return CTS_SUCCESS;
+}
+
+int helper_db_close(void)
+{
+       if (helper_db)
+       {
+               db_util_close(helper_db);
+               helper_db = NULL;
+       }
+
+       return CTS_SUCCESS;
+}
+
+int helper_begin_trans(void)
+{
+       int ret = -1;
+
+       ret = sqlite3_exec(helper_db, "BEGIN IMMEDIATE TRANSACTION",
+                       NULL, NULL, NULL);
+
+       while (SQLITE_BUSY == ret) {
+               sleep(1);
+               ret = sqlite3_exec(helper_db, "BEGIN IMMEDIATE TRANSACTION",
+                               NULL, NULL, NULL);
+       }
+
+       if (SQLITE_OK != ret)
+       {
+               ERR("sqlite3_exec() Failed(%d)", ret);
+               return CTS_ERR_DB_FAILED;
+       }
+       return CTS_SUCCESS;
+}
+
+#define CTS_COMMIT_TRY_MAX 3
+int helper_end_trans(bool success)
+{
+       int ret = -1, i=0;
+       char *errmsg = NULL;
+
+       if (success) {
+               ret = sqlite3_exec(helper_db, "COMMIT TRANSACTION",
+                               NULL, NULL, &errmsg);
+               if (SQLITE_OK != ret)
+               {
+                       ERR("sqlite3_exec(COMMIT) Failed(%d, %s)", ret, errmsg);
+                       sqlite3_free(errmsg);
+
+                       while (SQLITE_BUSY == ret && i<CTS_COMMIT_TRY_MAX) {
+                               i++;
+                               sleep(1);
+                               ret = sqlite3_exec(helper_db, "COMMIT TRANSACTION",
+                                               NULL, NULL, NULL);
+                       }
+                       if (SQLITE_OK != ret) {
+                               ERR("sqlite3_exec() Failed(%d)", ret);
+                               sqlite3_exec(helper_db, "ROLLBACK TRANSACTION",
+                                               NULL, NULL, NULL);
+                               return CTS_ERR_DB_FAILED;
+                       }
+               }
+       }
+       else {
+               sqlite3_exec(helper_db, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
+       }
+
+       return CTS_SUCCESS;
+}
+
+int helper_update_default_language(int prev_lang, int new_lang)
+{
+       int ret;
+       sqlite3* db = NULL;
+       char *errmsg = NULL;
+       char query[CTS_SQL_MIN_LEN] = {0};
+
+       ret = helper_db_open(&db);
+       h_retvm_if(CTS_SUCCESS != ret, ret, "helper_db_open() Failed(%d)", ret);
+
+       ret = helper_begin_trans();
+       h_retvm_if(ret, ret, "helper_begin_trans() Failed(%d)", ret);
+
+       snprintf(query, sizeof(query), "UPDATE %s SET %s=%d WHERE %s=%d",
+                       CTS_TABLE_DATA, CTS_SCHEMA_DATA_NAME_LANG_INFO, prev_lang,
+                       CTS_SCHEMA_DATA_NAME_LANG_INFO, CTS_LANG_DEFAULT);
+
+       ret = sqlite3_exec(db, query, NULL, NULL, &errmsg);
+       if (SQLITE_OK != ret)
+       {
+               ERR("sqlite3_exec(%s) Failed(%d, %s)", query, ret, errmsg);
+               sqlite3_free(errmsg);
+               helper_end_trans(false);
+               return CTS_ERR_DB_FAILED;
+       }
+
+       snprintf(query, sizeof(query), "UPDATE %s SET %s=%d WHERE %s=%d",
+                       CTS_TABLE_DATA, CTS_SCHEMA_DATA_NAME_LANG_INFO, CTS_LANG_DEFAULT,
+                       CTS_SCHEMA_DATA_NAME_LANG_INFO, new_lang);
+
+       ret = sqlite3_exec(db, query, NULL, NULL, &errmsg);
+       if (SQLITE_OK != ret)
+       {
+               ERR("sqlite3_exec(%s) Failed(%d, %s)", query, ret, errmsg);
+               sqlite3_free(errmsg);
+               helper_end_trans(false);
+               return CTS_ERR_DB_FAILED;
+       }
+
+       ret = helper_set_default_language(new_lang);
+       if (CTS_SUCCESS != ret) {
+               helper_end_trans(false);
+               return ret;
+       }
+       ret = helper_end_trans(true);
+       helper_db_close();
+
+       return ret;
+}
+
+int helper_insert_SDN_contact(const char *name, const char *number)
+{
+       int ret;
+       sqlite3* db = NULL;
+       sqlite3_stmt* stmt = NULL;
+       char query[CTS_SQL_MIN_LEN] = {0};
+
+       ret = helper_db_open(&db);
+       h_retvm_if(CTS_SUCCESS != ret, ret, "helper_db_open() Failed(%d)", ret);
+
+       snprintf(query, sizeof(query), "INSERT INTO %s(name, number) VALUES(?,?)",
+                       CTS_TABLE_SIM_SERVICES);
+
+       ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+       h_retvm_if(SQLITE_OK != ret, CTS_ERR_DB_FAILED,
+                       "sqlite3_prepare_v2(%s) Failed(%s)", query, sqlite3_errmsg(db));
+
+       sqlite3_bind_text(stmt, 1, name, strlen(name), SQLITE_STATIC);
+       sqlite3_bind_text(stmt, 2, number, strlen(number), SQLITE_STATIC);
+
+       ret = sqlite3_step(stmt);
+       if (SQLITE_DONE != ret)
+       {
+               ERR("sqlite3_step() Failed(%d)", ret);
+               sqlite3_finalize(stmt);
+               return CTS_ERR_DB_FAILED;
+       }
+       sqlite3_finalize(stmt);
+
+       helper_db_close();
+       return CTS_SUCCESS;
+}
+
+int helper_delete_SDN_contact(void)
+{
+       int ret;
+       sqlite3* db = NULL;
+       sqlite3_stmt* stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       ret = helper_db_open(&db);
+       h_retvm_if(CTS_SUCCESS != ret, ret, "helper_db_open() Failed(%d)", ret);
+
+       snprintf(query, sizeof(query), "DELETE FROM %s", CTS_TABLE_SIM_SERVICES);
+
+       ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+       h_retvm_if(SQLITE_OK != ret, CTS_ERR_DB_FAILED,
+                       "sqlite3_prepare_v2(%s) Failed(%s)", query, sqlite3_errmsg(db));
+
+       ret = sqlite3_step(stmt);
+       if (SQLITE_DONE != ret)
+       {
+               ERR("sqlite3_step() Failed(%d)", ret);
+               sqlite3_finalize(stmt);
+               return CTS_ERR_DB_FAILED;
+       }
+       sqlite3_finalize(stmt);
+
+       helper_db_close();
+       return CTS_SUCCESS;
+}
+
+static inline int helper_get_display_name(char *display, char *first,
+               char *last, char *dest, int dest_size)
+{
+       if (display) {
+               snprintf(dest, dest_size, "%s", display);
+       }
+       else {
+               if (NULL == first && NULL == last)
+                       return CTS_ERR_NO_DATA;
+               if (!last)
+                       snprintf(dest, dest_size, "%s", first);
+               else if (!first)
+                       snprintf(dest, dest_size, "%s", last);
+               else if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       snprintf(dest, dest_size, "%s %s", first, last);
+               else
+                       snprintf(dest, dest_size, "%s, %s", last, first);
+       }
+       return CTS_SUCCESS;
+}
+
+int helper_update_collation()
+{
+       int ret;
+       sqlite3* db = NULL;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MIN_LEN] = {0};
+       char sortkey[CTS_SQL_MIN_LEN];
+       char dest[CTS_SQL_MIN_LEN];
+
+       ret = helper_db_open(&db);
+       h_retvm_if(CTS_SUCCESS != ret, ret, "helper_db_open() Failed(%d)", ret);
+
+       ret = helper_begin_trans();
+       if(CTS_SUCCESS != ret) {
+               ERR("helper_begin_trans() Failed(%d)", ret);
+               helper_db_close();
+               return ret;
+       }
+
+       snprintf(query, sizeof(query),
+                       "SELECT contact_id, data2, data3, data5 FROM %s WHERE datatype = %d",
+                       CTS_TABLE_DATA, CTS_DATA_NAME);
+       ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+       if(SQLITE_OK != ret) {
+               ERR("sqlite3_prepare_v2(%s) Failed(%s)", query, sqlite3_errmsg(db));
+               helper_end_trans(false);
+               helper_db_close();
+               return CTS_ERR_DB_FAILED;
+       }
+
+       while (SQLITE_ROW == (ret = sqlite3_step(stmt))) {
+               cts_stmt update_stmt = NULL;
+               int contact_id = sqlite3_column_int(stmt, 0);
+               char *first = (char*)sqlite3_column_text(stmt, 1);
+               char *last = (char*)sqlite3_column_text(stmt, 2);
+               char *display = (char*)sqlite3_column_text(stmt, 3);
+
+               ret = helper_get_display_name(display, first, last, dest, sizeof(dest));
+               if (CTS_SUCCESS != ret)
+                       continue;
+
+               ret = helper_collation_str(dest, sortkey, sizeof(sortkey));
+               if (CTS_SUCCESS != ret) {
+                       ERR("helper_collation_str() Failed(%d)", ret);
+                       sqlite3_finalize(stmt);
+                       helper_end_trans(false);
+                       helper_db_close();
+                       return CTS_ERR_DB_FAILED;
+               }
+               snprintf(query, sizeof(query), "UPDATE %s SET %s=? WHERE contact_id=%d",
+                               CTS_TABLE_DATA, CTS_SCHEMA_DATA_NAME_SORTING_KEY,
+                               contact_id);
+               ret = sqlite3_prepare_v2(db, query, strlen(query), &update_stmt, NULL);
+               if(SQLITE_OK != ret) {
+                       ERR("sqlite3_prepare_v2(%s) Failed(%s)", query, sqlite3_errmsg(db));
+                       sqlite3_finalize(stmt);
+                       helper_end_trans(false);
+                       helper_db_close();
+                       return CTS_ERR_DB_FAILED;
+               }
+
+               sqlite3_bind_text(update_stmt, 1, sortkey, strlen(sortkey), SQLITE_STATIC);
+               HELPER_DBG("query : %s", query);
+               ret = sqlite3_step(update_stmt);
+               if (SQLITE_DONE != ret) {
+                       ERR("sqlite3_exec(%s) Failed(%d, %s)", query, ret, sqlite3_errmsg(db));
+                       sqlite3_finalize(stmt);
+                       sqlite3_finalize(update_stmt);
+                       helper_end_trans(false);
+                       helper_db_close();
+                       return CTS_ERR_DB_FAILED;
+               }
+               sqlite3_finalize(update_stmt);
+       }
+
+       if (SQLITE_ROW != ret && SQLITE_DONE != ret) {
+               ERR("sqlite3_step() Failed(%d)", ret);
+               sqlite3_finalize(stmt);
+               helper_end_trans(false);
+               helper_db_close();
+               return CTS_ERR_DB_FAILED;
+       }
+
+       sqlite3_finalize(stmt);
+
+       ret = helper_end_trans(true);
+       if (CTS_SUCCESS == ret) {
+               int fd = open(CTS_NOTI_CONTACT_CHANGED_DEF, O_TRUNC | O_RDWR);
+               if (0 <= fd)
+                       close(fd);
+       }
+       helper_db_close();
+
+       return ret;
+}
diff --git a/helper/sqlite.h b/helper/sqlite.h
new file mode 100755 (executable)
index 0000000..a2b5368
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_HELPER_SQLITE_H__
+#define __CTS_HELPER_SQLITE_H__
+
+#include <sqlite3.h>
+
+int helper_db_open(sqlite3 **db);
+int helper_db_close(void);
+int helper_update_default_language(int system_lang, int default_lang);
+int helper_insert_SDN_contact(const char *name, const char *number);
+int helper_delete_SDN_contact(void);
+int helper_update_collation();
+
+#endif // __CTS_HELPER_SQLITE_H__
+
+
diff --git a/helper/utils.c b/helper/utils.c
new file mode 100755 (executable)
index 0000000..b03857b
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <malloc.h>
+#include <contacts-svc.h>
+#include <vconf.h>
+#include <vconf-keys.h>
+
+#include "cts-utils.h"
+#include "internal.h"
+#include "sim.h"
+#include "sqlite.h"
+#include "normalize.h"
+#include "localize.h"
+#include "utils.h"
+
+static const char *HELPER_VCONF_TAPI_SIM_PB_INIT = VCONFKEY_TELEPHONY_SIM_PB_INIT;
+static const char *HELPER_VCONF_SYSTEM_LANGUAGE = VCONFKEY_LANGSET;
+static const char *HELPER_VCONF_DISPLAY_ORDER = CTS_VCONF_DISPLAY_ORDER_DEF;
+
+static int default_language = -1;
+static int system_language = -1;
+
+static inline int helper_get_system_language(void)
+{
+       return system_language;
+}
+
+inline int helper_set_default_language(int lang)
+{
+       int ret = vconf_set_int(CTS_VCONF_DEFAULT_LANGUAGE, lang);
+       h_retvm_if(ret<0, CTS_ERR_VCONF_FAILED, "vconf_set_int() Failed(%d)", ret);
+
+       default_language = lang;
+       return CTS_SUCCESS;
+}
+
+static void helper_change_language_cb(keynode_t *key, void *data)
+{
+       int ret = -1;
+       const char *langset;
+
+       langset = vconf_keynode_get_str(key);
+       if (!default_language) {
+               ret = vconf_get_int(CTS_VCONF_DEFAULT_LANGUAGE, &default_language);
+               h_retm_if(ret<0, "vconf_get_int() Failed(%d)", ret);
+       }
+
+       system_language = helper_get_language_type(langset);
+       if (system_language != default_language)
+               ret = helper_update_default_language(default_language, system_language);
+}
+
+static void helper_update_collation_cb(keynode_t *key, void *data)
+{
+       helper_update_collation();
+}
+
+static void helper_tapi_sim_complete_cb(keynode_t *key, void *data)
+{
+       int ret, init_stat;
+       init_stat = vconf_keynode_get_int(key);
+       if (VCONFKEY_TELEPHONY_SIM_PB_INIT_COMPLETED == init_stat) {
+               ret = helper_sim_read_SDN(NULL);
+               h_warn_if(CTS_SUCCESS != ret, "helper_sim_read_SDN() Failed(%d)", ret);
+
+               vconf_ignore_key_changed(HELPER_VCONF_TAPI_SIM_PB_INIT, helper_tapi_sim_complete_cb);
+       }
+}
+
+void helper_final_configuration(void)
+{
+       int ret = -1;
+
+       ret = vconf_ignore_key_changed(HELPER_VCONF_SYSTEM_LANGUAGE, helper_change_language_cb);
+       h_retm_if(ret<0,"vconf_ignore_key_changed(%s) Failed(%d)",HELPER_VCONF_SYSTEM_LANGUAGE,ret);
+
+       ret = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, helper_update_collation_cb);
+       h_retm_if(ret<0,"vconf_ignore_key_changed(%s) Failed(%d)",VCONFKEY_REGIONFORMAT,ret);
+
+       ret = vconf_ignore_key_changed(HELPER_VCONF_DISPLAY_ORDER, helper_update_collation_cb);
+       h_retm_if(ret<0,"vconf_ignore_key_changed(%s) Failed(%d)",VCONFKEY_REGIONFORMAT,ret);
+}
+
+int helper_init_configuration(void)
+{
+       int ret, sim_stat=-1;
+       const char *langset;
+
+       ret = vconf_get_int(CTS_VCONF_DEFAULT_LANGUAGE, &default_language);
+       if (ret < 0) {
+               ERR("vconf_get_int(%s) Failed(%d)",CTS_VCONF_DEFAULT_LANGUAGE ,ret);
+               default_language = 0;
+       }
+
+       ret = vconf_notify_key_changed(HELPER_VCONF_SYSTEM_LANGUAGE,
+                       helper_change_language_cb, NULL);
+       h_retvm_if(ret<0, CTS_ERR_VCONF_FAILED, "vconf_notify_key_changed(%s) Failed(%d)",
+                       HELPER_VCONF_SYSTEM_LANGUAGE, ret);
+
+       ret = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT,
+                       helper_update_collation_cb, NULL);
+       h_retvm_if(ret<0, CTS_ERR_VCONF_FAILED, "vconf_notify_key_changed(%s) Failed(%d)",
+                       VCONFKEY_REGIONFORMAT, ret);
+
+       ret = vconf_notify_key_changed(HELPER_VCONF_DISPLAY_ORDER,
+                       helper_update_collation_cb, NULL);
+       h_retvm_if(ret<0, CTS_ERR_VCONF_FAILED, "vconf_notify_key_changed(%s) Failed(%d)",
+                       HELPER_VCONF_DISPLAY_ORDER, ret);
+
+       langset = vconf_get_str(HELPER_VCONF_SYSTEM_LANGUAGE);
+       h_warn_if(NULL == langset, "vconf_get_str(%s) return NULL", HELPER_VCONF_SYSTEM_LANGUAGE);
+
+       system_language = helper_get_language_type(langset);
+       if (system_language != default_language) {
+               ERR("system lang(%s, %d), default lang(%d)", langset, system_language, default_language);
+               helper_update_default_language(default_language, system_language);
+       }
+
+       ret = vconf_get_int(HELPER_VCONF_TAPI_SIM_PB_INIT, &sim_stat);
+       if (VCONFKEY_TELEPHONY_SIM_PB_INIT_COMPLETED == sim_stat) {
+               ret = helper_sim_read_SDN(NULL);
+               h_warn_if(CTS_SUCCESS != ret, "helper_sim_read_SDN() Failed(%d)", ret);
+       } else {
+               ret = vconf_notify_key_changed(HELPER_VCONF_TAPI_SIM_PB_INIT,
+                               helper_tapi_sim_complete_cb, NULL);
+               h_retvm_if(ret<0, CTS_ERR_VCONF_FAILED, "vconf_notify_key_changed(%s) Failed(%d)",
+                               HELPER_VCONF_TAPI_SIM_PB_INIT, ret);
+       }
+
+       return CTS_SUCCESS;
+}
+
+void helper_trim_memory(void)
+{
+       malloc_trim(0);
+       sqlite3_release_memory(-1);
+}
diff --git a/helper/utils.h b/helper/utils.h
new file mode 100755 (executable)
index 0000000..fe27385
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Contacts Service Helper
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_HELPER_UTILS_H__
+#define __CTS_HELPER_UTILS_H__
+
+int helper_init_configuration(void);
+void helper_final_configuration(void);
+
+int helper_get_default_language(void);
+int helper_set_default_language(int lang);
+
+void helper_trim_memory(void);
+
+#endif // __CTS_HELPER_UTILS_H__
+
diff --git a/image/SLP_ContactsService_PG_image001.PNG b/image/SLP_ContactsService_PG_image001.PNG
new file mode 100755 (executable)
index 0000000..36ff225
Binary files /dev/null and b/image/SLP_ContactsService_PG_image001.PNG differ
diff --git a/include/ContactsService_PG.h b/include/ContactsService_PG.h
new file mode 100755 (executable)
index 0000000..49a344f
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ *
+ * @ingroup   SLP_PG
+ * @defgroup  CONTACTS_SVC_PG Contacts Service
+
+
+<h1 class="pg">Introduction</h1>
+       <h2 class="pg">Purpose of this document</h2>
+
+The purpose of this document is to describe how applications can use contacts-service APIs for handling contact's information. This document gives programming guidelines to application engineers and examples of using contact data.
+
+       <h2 class="pg">Scope</h2>
+
+The scope of this document is limited to Contacts-service API usage.
+
+
+<h1 class="pg">Contacts Service Architecture</h1>
+       <h2 class="pg"> Overview</h2>
+
+Contacts-service is responsible for inserting, deleting, and updating contact data in order to accommodate the needs for application's contact data.
+Users can access contacts data without knowing DB schema, SQLite, relations of data
+
+@image html SLP_ContactsService_PG_image001.PNG
+
+
+       <h2 class="pg">Sub-Components</h2>
+
+Contacts-svc-helper is a process for contacts-servcie. The process wait requests of contacts-service library and respond immediately
+
+
+
+<h1 class="pg">Contacts Service Features</h1>
+       - Similar to Sqlite3
+       - Handle information of Contact
+       - Handle information of Group
+       - Handle information of Phone log
+
+       <h2 class="pg">Similar to Sqlite3</h2>
+Contacts-service API is similar to Sqlite3.
+
+       <h2 class="pg">Handle information of Contact</h2>
+Contacts-service supports to insert/update/delete/get/search information of contact.
+The Information of contact includes name, numbers, emails, addresses, company, messenger, events, group relation information, web sites and favorite information.
+
+       <h2 class="pg">Handle information of Group</h2>
+Contacts-service supports to insert/update/delete/get information of contact.
+
+       <h2 class="pg">Handle information of Group</h2>
+Contacts-service supports to insert/update/delete/get information of Phone log.
+
+<h1 class="pg">Contacts Service API Description</h1>
+
+you can refer @ref CONTACTS_SVC
+
+
+
+<h1 class="pg">Sample Code</h1>
+
+       <h2 class="pg">Connect to Contact Database</h2>
+
+Before using contact information from contacts service API, caller module should connect to the contact database, and after finishing with the contact information, should disconnect from the contact database
+
+@code
+int contacts_svc_connect(void);
+
+int contacts_svc_disconnect(void);
+@endcode
+
+
+       <h2 class="pg">Insert information of contact</h2>
+
+@code
+
+void insert_test(void)
+{
+   CTSstruct *contact;
+   CTSvalue *name, *number1, *number2;
+   GSList *numbers=NULL;
+   contact = contacts_svc_struct_new(CTS_STRUCT_CONTACT);
+
+   name = contacts_svc_value_new(CTS_VALUE_CONTACT_BASE_INFO);
+   if(name) {
+      contacts_svc_value_set_str(name, CTS_BASE_VAL_IMG_PATH_STR, "test.vcf");
+   }
+   contacts_svc_struct_store_value(contact, CTS_CF_BASE_INFO_VALUE, name);
+   contacts_svc_value_free(name);
+
+
+   name = contacts_svc_value_new(CTS_VALUE_NAME);
+   if(name) {
+      contacts_svc_value_set_str(name, CTS_NAME_VAL_FIRST_STR, "Gil-Dong");
+      contacts_svc_value_set_str(name, CTS_NAME_VAL_LAST_STR, "Hong");
+      contacts_svc_value_set_str(name, CTS_NAME_VAL_SUFFIX_STR, "engineer");
+   }
+   contacts_svc_struct_store_value(contact, CTS_CF_NAME_VALUE, name);
+   contacts_svc_value_free(name);
+
+   number1 = contacts_svc_value_new(CTS_VALUE_NUMBER);
+   if(number1) {
+      contacts_svc_value_set_str(number1, CTS_NUM_VAL_NUMBER_STR, "0987654321");
+      contacts_svc_value_set_int(number1, CTS_NUM_VAL_TYPE_INT, CTS_NUM_TYPE_CELL);
+      contacts_svc_value_set_bool(number1, CTS_NUM_VAL_DEFAULT_BOOL, true);
+   }
+   numbers = g_slist_append(numbers, number1);
+
+   number2 = contacts_svc_value_new(CTS_VALUE_NUMBER);
+   if(number2) {
+      contacts_svc_value_set_str(number2, CTS_NUM_VAL_NUMBER_STR, "0123456789");
+      contacts_svc_value_set_int(number2, CTS_NUM_VAL_TYPE_INT,
+                                 CTS_NUM_TYPE_WORK);
+   }
+   numbers = g_slist_append(numbers, number2);
+
+   contacts_svc_struct_store_list(contact, CTS_CF_NUMBER_LIST, numbers);
+   contacts_svc_value_free(number1);
+   contacts_svc_value_free(number2);
+   g_slist_free(numbers);
+
+   contacts_svc_insert_contact(0, contact);
+   contacts_svc_struct_free(contact);
+}
+@endcode
+
+
+       <h2 class="pg">Get contact</h2>
+
+@code
+void get_contact(CTSstruct *contact)
+{
+   int index=0, ret=-1;
+   CTSvalue *value=NULL;
+   GSList *get_list, *cursor;
+
+   if(!contact) {
+      index = contacts_svc_find_contact_by(CTS_FIND_BY_NUMBER, "0123456789");
+      if(index > CTS_SUCCESS)
+        ret = contacts_svc_get_contact(index, &contact);
+      if(ret < 0)
+      {
+         printf("No found record\n");
+         return;
+      }
+   }
+   contacts_svc_struct_get_value(contact, CTS_CF_NAME_VALUE, &value);
+   printf("First Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_FIRST_STR));
+   printf("Last Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_LAST_STR));
+   printf("Additional Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_ADDITION_STR));
+   printf("Display Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_DISPLAY_STR));
+   printf("Prefix Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_PREFIX_STR));
+   printf("Suffix Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_SUFFIX_STR));
+
+   value = NULL;
+   contacts_svc_struct_get_value(contact, CTS_CF_COMPANY_VALUE, &value);
+   printf("Company Name : %s\n", contacts_svc_value_get_str(value, CTS_COMPANY_VAL_NAME_STR));
+   printf("Company Department : %s\n", contacts_svc_value_get_str(value, CTS_COMPANY_VAL_DEPARTMENT_STR));
+
+   get_list = NULL;
+   contacts_svc_struct_get_list(contact, CTS_CF_NUMBER_LIST, &get_list);
+
+   cursor = get_list;
+   for(;cursor;cursor=g_slist_next(cursor))
+   {
+      printf("number Type = %d",
+         contacts_svc_value_get_int(cursor->data, CTS_NUM_VAL_TYPE_INT));
+      if(contacts_svc_value_get_bool(cursor->data, CTS_NUM_VAL_FAVORITE_BOOL))
+         printf("(favorite)");
+      printf("Number = %s\n",
+         contacts_svc_value_get_str(cursor->data, CTS_NUM_VAL_NUMBER_STR));
+      if(index)
+         contacts_svc_insert_favorite(contacts_svc_value_get_int(cursor->data, CTS_NUM_VAL_ID_INT));
+   }
+
+   get_list = NULL;
+   contacts_svc_struct_get_list(contact, CTS_CF_EMAIL_LIST, &get_list);
+
+   cursor = get_list;
+   for(;cursor;cursor=g_slist_next(cursor))
+   {
+      printf("email Type = %d",
+         contacts_svc_value_get_int(cursor->data, CTS_EMAIL_VAL_TYPE_INT));
+
+      printf("email = %s\n",
+         contacts_svc_value_get_str(cursor->data, CTS_EMAIL_VAL_ADDR_STR));
+   }
+
+   get_list = NULL;
+   contacts_svc_struct_get_list(contact, CTS_CF_GROUPREL_LIST, &get_list);
+   cursor = get_list;
+   for(;cursor;cursor=g_slist_next(cursor))
+   {
+      printf("group = %s:",
+         contacts_svc_value_get_str(cursor->data, CTS_GROUPREL_VAL_NAME_STR));
+
+      printf("%d\n",
+         contacts_svc_value_get_int(cursor->data, CTS_GROUPREL_VAL_ID_INT));
+   }
+
+
+   if(index)
+      contacts_svc_struct_free(contact);
+
+}
+@endcode
+
+
+       <h2 class="pg">Get contact list</h2>
+
+@code
+void get_contact_list(void)
+{
+   CTSiter *iter = NULL;
+   contacts_svc_get_list(CTS_LIST_ALL_CONTACT, &iter);
+
+   while(CTS_SUCCESS == contacts_svc_iter_next(iter))
+   {
+      CTSvalue *contact = NULL;
+      const char *first, *last, *display;
+      contact = contacts_svc_iter_get_info(iter);
+
+      printf("(%8d)", contacts_svc_value_get_int(contact, CTS_LIST_CONTACT_ID_INT));
+      display = contacts_svc_value_get_str(contact, CTS_LIST_CONTACT_DISPLAY_STR);
+      if(display)
+         printf("%s :", display);
+      else
+      {
+         first = contacts_svc_value_get_str(contact, CTS_LIST_CONTACT_FIRST_STR);
+         last = contacts_svc_value_get_str(contact, CTS_LIST_CONTACT_LAST_STR);
+         if(CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+            printf("%s %s :", first, last);
+         else
+            printf("%s %s :", last, first);
+      }
+      printf("%s", contacts_svc_value_get_str(contact, CTS_LIST_CONTACT_IMG_PATH_STR));
+      printf("\n");
+      contacts_svc_value_free(contact);
+   }
+   contacts_svc_iter_remove(iter);
+}
+@endcode
+
+
+       <h2 class="pg">Delete contact </h2>
+
+@code
+
+void delete_test(void)
+{
+   //get contact
+   int index=0, ret=-1;
+   CTSstruct *contact;
+
+   if(!contact) {
+      index = contacts_svc_find_contact_by(CTS_FIND_BY_NUMBER, "0123456789");
+      if(index > CTS_SUCCESS)
+        ret = contacts_svc_get_contact(index, &contact);
+      if(ret < 0)
+      {
+         printf("No found record\n");
+         return;
+      }
+   }
+
+   contacts_svc_delete_contact(index);
+
+   contacts_svc_struct_free(contact);
+
+}
+
+@endcode
+
+       <h2 class="pg">Search contacts by name </h2>
+
+@code
+void search_contacts_by_name(void)
+{
+   int ret;
+   CTSiter *iter = NULL;
+   ret = contacts_svc_get_list_with_str(CTS_LIST_CONTACTS_WITH_NAME,
+      "Hong", &iter);
+   if(CTS_SUCCESS != ret) return;
+
+   while(CTS_SUCCESS == contacts_svc_iter_next(iter))
+   {
+      CTSvalue *row_info = NULL;
+      const char *first, *last, *display;
+      row_info = contacts_svc_iter_get_info(iter);
+
+      printf("(%8d)", contacts_svc_value_get_int(row_info, CTS_LIST_CONTACT_ID_INT));
+
+      display = contacts_svc_value_get_str(row_info, CTS_LIST_CONTACT_DISPLAY_STR);
+      if(display)
+         printf("%s :", display);
+      else
+      {
+         first = contacts_svc_value_get_str(row_info, CTS_LIST_CONTACT_FIRST_STR);
+         last = contacts_svc_value_get_str(row_info, CTS_LIST_CONTACT_LAST_STR);
+         if(CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+            printf("%s %s :", first, last);
+         else
+            printf("%s %s :", last, first);
+      }
+      printf("%s", contacts_svc_value_get_str(row_info, CTS_LIST_CONTACT_IMG_PATH_STR));
+      printf("\n");
+      contacts_svc_value_free(row_info);
+   }
+   contacts_svc_iter_remove(iter);
+}
+@endcode
+
+ * @}
+ */
+
diff --git a/include/contacts-svc-struct.head b/include/contacts-svc-struct.head
new file mode 100755 (executable)
index 0000000..a0242be
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CONTACTS_SVC_STRUCT_H__
+#define __CONTACTS_SVC_STRUCT_H__
+
+#include <stdbool.h>
+#include <glib.h>
+
+/**
+ * @defgroup   CONTACTS_SVC_STRUCT Structs & values
+ * @ingroup    CONTACTS_SVC
+ * @addtogroup CONTACTS_SVC_STRUCT
+ * @{
+ *
+ * This interface provides methods to handle Structs (= collection of values)\r
+ * and values of contacts service (individual properties of a contact).\r
+ *
+ * @section sec1 Properties and Policies
+ * - Memory always has to be freed by its creator, unless stated otherwise.
+ * \n contacts_svc_struct_store_XXX means "copy".
+ * But If list has a same start with contacts struct(#CTSstruct), it is not "copy"(just appendix)
+ * - Contacts structs(#CTSstruct) own data stored in them.(User cannot free each value in struct)
+ * - Contacts_svc_value_XXXX is called by reference.
+ * \n But Contacts_svc_value_set_str() is called by value for the data in contacts struct(#CTSstruct).
+ * - All "char *" strings use UTF-8 encoding.
+ *
+ */
+
diff --git a/include/contacts-svc-struct.tail b/include/contacts-svc-struct.tail
new file mode 100755 (executable)
index 0000000..6ea9abc
--- /dev/null
@@ -0,0 +1,6 @@
+
+/**
+ * @}
+ */
+
+#endif //__CONTACTS_SVC_STRUCT_H__
diff --git a/include/contacts-svc-sub.head b/include/contacts-svc-sub.head
new file mode 100755 (executable)
index 0000000..e891d16
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CONTACTS_SVC_SUB_H__
+#define __CONTACTS_SVC_SUB_H__
+
diff --git a/include/contacts-svc-sub.tail b/include/contacts-svc-sub.tail
new file mode 100755 (executable)
index 0000000..d2263ff
--- /dev/null
@@ -0,0 +1,2 @@
+
+#endif //__CONTACTS_SVC_SUB_H__
diff --git a/include/contacts-svc.head b/include/contacts-svc.head
new file mode 100755 (executable)
index 0000000..fcb5cd5
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CONTACTS_SVC_H__
+#define __CONTACTS_SVC_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <contacts-svc-struct.h>
+#include <contacts-svc-sub.h>
+
+/**
+ * This header file contains the declaration & description of Contacts Service.
+ *
+ * @defgroup   CONTACTS_SVC Contacts Service
+ * @ingroup    PIMS_SVC
+ * @brief   Contacts Service
+ *
+ * Contacts Service supports APIs that insert, delete, and update contact data
+ * in order to accommodate the needs for application's contact data processing.
+ *
+ * @section Header To use Them:
+ * @code
+ * #include <contacts-svc.h>
+ * @endcode
+ *
+ */
+
+/**
+ * @addtogroup CONTACTS_SVC
+ * @{
+ */
+
diff --git a/include/contacts-svc.tail b/include/contacts-svc.tail
new file mode 100644 (file)
index 0000000..cddb7e1
--- /dev/null
@@ -0,0 +1,9 @@
+
+/**
+ * @}
+ */
+#ifdef __cplusplus
+   }
+#endif
+
+#endif //__CONTACTS_SVC_H__
diff --git a/packaging/contacts-service.spec b/packaging/contacts-service.spec
new file mode 100644 (file)
index 0000000..f86c8e3
--- /dev/null
@@ -0,0 +1,84 @@
+Name:       contacts-service
+Summary:    Contacts Service
+Version:    0.4.2
+Release:    1
+Group:      TO_BE/FILLED_IN
+License:    Apache 2.0
+Source0:    %{name}-%{version}.tar.gz
+Requires(post): /sbin/ldconfig
+Requires(post): /usr/bin/sqlite3
+Requires(post): /usr/bin/vconftool
+Requires(postun): /sbin/ldconfig
+BuildRequires:  cmake
+BuildRequires:  vconf-keys-devel
+BuildRequires:  pkgconfig(db-util)
+BuildRequires:  pkgconfig(vconf)
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:  pkgconfig(sqlite3)
+BuildRequires:  pkgconfig(tapi)
+BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  pkgconfig(icu-i18n)
+
+%description
+Contacts Service Library
+
+%package devel
+Summary:    Contacts Service  (devel)
+Group:      Development/Libraries
+Requires:   %{name} = %{version}-%{release}
+
+%description devel
+Contacts Service Library (devel)
+
+%prep
+%setup -q
+
+
+%build
+cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix}
+
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+%post 
+/sbin/ldconfig
+contacts-svc-helper schema
+chown :6005 /opt/dbspace/.contacts-svc.db
+chown :6005 /opt/dbspace/.contacts-svc.db-journal
+
+vconftool set -t int db/service/contacts/default_lang 1
+vconftool set -t int db/service/contacts/name_sorting_order 0 -g 6005
+vconftool set -t int db/service/contacts/name_display_order 0 -g 6005
+
+#mkdir -p %{buildroot}%{_sysconfdir}/rc.d/
+#mkdir -p %{buildroot}%{_sysconfdir}/rc.d/rc3.d/
+#mkdir -p %{buildroot}%{_sysconfdir}/rc.d/rc5.d/
+#ln -s %{buildroot}/%{_sysconfdir}/init.d/contacts-svc-helper.sh %{buildroot}%/{_sysconfdir}/rc.d/rc3.d/S50contacts-svc-helper
+#ln -s %{buildroot}/%{_sysconfdir}/init.d/contacts-svc-helper.sh %{buildroot}%/{_sysconfdir}/rc.d/rc5.d/S50contacts-svc-helper
+
+mkdir -p /etc/rc.d/
+mkdir -p /etc/rc.d/rc3.d/
+mkdir -p /etc/rc.d/rc5.d/
+ln -s /etc/init.d/contacts-svc-helper.sh /etc/rc.d/rc3.d/S50contacts-svc-helper
+ln -s /etc/init.d/contacts-svc-helper.sh /etc/rc.d/rc5.d/S50contacts-svc-helper
+
+
+%postun -p /sbin/ldconfig
+
+
+%files
+%defattr(-,root,root,-)
+%attr(0660,root,db_contact)/opt/data/contacts-svc/.CONTACTS_SVC_*
+%{_libdir}/libcontacts-service.so*
+%{_bindir}/contacts-svc-helper
+%attr(0755,root,root) /etc/rc.d/init.d/contacts-svc-helper.sh
+
+%files devel
+%defattr(-,root,root,-)
+%{_libdir}/*.so
+%{_libdir}/pkgconfig/contacts-service.pc
+%{_includedir}/contacts-svc/*.h
diff --git a/schema.sql b/schema.sql
new file mode 100755 (executable)
index 0000000..99ebfee
--- /dev/null
@@ -0,0 +1,220 @@
+--
+-- Contacts Service
+--
+-- Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+--
+-- Contact: Youngjae Shin <yj99.shin@samsung.com>
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+--PRAGMA journal_mode = PERSIST;
+--PRAGMA journal_mode = TRUNCATE;
+
+CREATE TABLE addressbooks
+(
+addrbook_id INTEGER PRIMARY KEY AUTOINCREMENT,
+addrbook_name TEXT,
+acc_id INTEGER,
+acc_type INTEGER DEFAULT 0,
+mode INTEGER, -- permission
+last_sync_ver INTEGER
+);
+--CREATE TRIGGER trg_addressbook_sync AFTER UPDATE OF last_sync_ver ON addressbooks
+-- BEGIN
+--   DELETE FROM deleteds WHERE addrbook_id = new.addrbook_id and deleted_time <= new.last_sync_ver;
+-- END;
+CREATE TRIGGER trg_addressbook_del AFTER DELETE ON addressbooks
+ BEGIN
+   DELETE FROM groups WHERE addrbook_id = old.addrbook_id;
+   DELETE FROM contacts WHERE addrbook_id = old.addrbook_id;
+   DELETE FROM deleteds WHERE addrbook_id = old.addrbook_id;
+ END;
+
+CREATE TABLE contacts
+(
+contact_id INTEGER PRIMARY KEY AUTOINCREMENT,
+addrbook_id INTEGER NOT NULL DEFAULT 0,
+default_num INTEGER,
+default_email INTEGER,
+default_addr INTEGER,
+is_favorite INTEGER DEFAULT 0,
+created_ver INTEGER NOT NULL,
+changed_ver INTEGER NOT NULL,
+changed_time INTEGER NOT NULL,
+outgoing_count INTEGER DEFAULT 0,
+uid TEXT,
+ringtone TEXT,
+note TEXT,
+image0 TEXT, -- normal image
+image1 TEXT, -- full image
+person_id INTEGER
+);
+CREATE INDEX contacts_ver_idx ON contacts(changed_ver);
+CREATE INDEX contacts_person_idx ON contacts(person_id);
+CREATE TRIGGER trg_contacts_del AFTER DELETE ON contacts
+ BEGIN
+   DELETE FROM data WHERE contact_id = old.contact_id;
+   DELETE FROM group_relations WHERE old.addrbook_id != -1 AND contact_id = old.contact_id;
+   DELETE FROM favorites WHERE type = 0 AND related_id = old.contact_id;
+ END;
+
+CREATE TABLE deleteds
+(
+contact_id INTEGER,
+addrbook_id INTEGER,
+deleted_ver INTEGER
+);
+CREATE INDEX deleteds_ver_idx ON deleteds(deleted_ver);
+
+CREATE TABLE cts_version
+(
+ver INTEGER PRIMARY KEY
+);
+INSERT INTO cts_version VALUES(0);
+
+CREATE TABLE sim_services
+(
+id INTEGER PRIMARY KEY AUTOINCREMENT,
+type INTEGER,
+name TEXT,
+number TEXT
+);
+
+CREATE TABLE custom_types
+(
+id INTEGER PRIMARY KEY AUTOINCREMENT,
+class INTEGER,
+name TEXT,
+UNIQUE(class, name)
+);
+CREATE INDEX idx_custom_type ON custom_types(class, name);
+CREATE TRIGGER trg_custom_types_del AFTER DELETE ON custom_types
+ BEGIN
+        UPDATE data SET data1 = 0 WHERE old.class = 1 AND number_type = old.id AND datatype = 8;
+ END;
+
+CREATE TABLE data
+(
+id INTEGER PRIMARY KEY AUTOINCREMENT,
+contact_id INTEGER NOT NULL,
+datatype INTEGER NOT NULL,
+data1 INTEGER,
+data2 TEXT,
+data3 TEXT,
+data4 TEXT,
+data5 TEXT,
+data6 TEXT,
+data7 TEXT,
+data8 TEXT,
+data9 TEXT,
+data10 TEXT,
+person_id INTEGER
+);
+CREATE TRIGGER trg_data_number_del AFTER DELETE ON data
+ WHEN old.datatype = 8
+ BEGIN
+   DELETE FROM favorites WHERE  type = 1 AND related_id = old.id;
+   DELETE FROM speeddials WHERE  number_id = old.id;
+ END;
+CREATE INDEX data_contact_idx ON data(contact_id);
+CREATE INDEX data_contact_idx2 ON data(datatype, contact_id);
+CREATE INDEX data_idx1 ON data(data1);
+CREATE INDEX data_idx2 ON data(data2);
+CREATE INDEX data_idx3 ON data(data3);
+CREATE INDEX data_idx4 ON data(data4);
+CREATE INDEX data_idx5 ON data(data5);
+CREATE INDEX data_idx6 ON data(data6);
+CREATE INDEX data_idx7 ON data(data7);
+CREATE INDEX data_idx8 ON data(data8);
+CREATE INDEX data_idx9 ON data(data9);
+CREATE INDEX data_idx10 ON data(data10);
+CREATE INDEX data_person_idx ON data(person_id);
+
+CREATE TABLE groups
+(
+group_id INTEGER PRIMARY KEY AUTOINCREMENT,
+addrbook_id INTEGER,
+group_name TEXT,
+ringtone TEXT,
+UNIQUE(addrbook_id, group_name)
+);
+CREATE TRIGGER trg_groups_del AFTER DELETE ON groups
+ BEGIN
+   DELETE FROM group_relations WHERE group_id = old.group_id;
+ END;
+
+CREATE TABLE group_relations
+(
+group_id INTEGER NOT NULL,
+contact_id INTEGER NOT NULL,
+UNIQUE(group_id, contact_id)
+);
+CREATE INDEX group_idx1 ON group_relations(contact_id);
+
+CREATE TABLE speeddials
+(
+speed_num INTEGER PRIMARY KEY NOT NULL,
+number_id INTEGER UNIQUE
+);
+
+CREATE TABLE favorites
+(
+id INTEGER PRIMARY KEY AUTOINCREMENT,
+type INTEGER NOT NULL,
+related_id INTEGER NOT NULL,
+favorite_prio REAL,
+UNIQUE(type, related_id)
+);
+CREATE INDEX idx1_favorites ON favorites(favorite_prio);
+CREATE INDEX idx2_favorites ON favorites(type, related_id);
+CREATE TRIGGER trg_favorite_del BEFORE DELETE ON favorites
+ BEGIN
+   UPDATE data SET data3 = 0 WHERE old.type = 1 AND id = old.related_id AND datatype = 8;
+   UPDATE contacts SET is_favorite = 0 WHERE old.type = 0 AND contact_id = old.related_id;
+ END;
+CREATE TRIGGER trg_favorite_insert AFTER INSERT ON favorites
+ BEGIN
+   UPDATE data SET data3 = 1 WHERE new.type = 1 AND id = new.related_id AND datatype = 8;
+   UPDATE contacts SET is_favorite = 1 WHERE new.type = 0 AND contact_id = new.related_id;
+ END;
+
+CREATE TABLE phonelogs
+(
+id INTEGER PRIMARY KEY AUTOINCREMENT,
+number TEXT,
+normal_num TEXT,
+related_id INTEGER, --contact_id
+log_type INTEGER,
+log_time INTEGER,
+data1 INTEGER, --duration, message_id
+data2 TEXT  -- short message
+);
+CREATE INDEX idx1_phonelogs ON phonelogs(log_type);
+CREATE INDEX idx2_phonelogs ON phonelogs(log_time);
+CREATE TRIGGER trg_phonelogs_del AFTER DELETE ON phonelogs
+ WHEN old.log_type = 2 OR old.log_type = 4
+ BEGIN
+   DELETE FROM phonelog_accumulation WHERE log_time < (old.log_time - 3456000); -- 40 days
+   INSERT INTO phonelog_accumulation VALUES(NULL, 1, old.log_time, old.data1);
+ END;
+
+CREATE TABLE phonelog_accumulation
+(
+id INTEGER PRIMARY KEY AUTOINCREMENT,
+log_cnt INTEGER,
+log_time INTEGER,
+duration INTEGER
+);
+INSERT INTO phonelog_accumulation VALUES(1, 0, NULL, 0);
+INSERT INTO phonelog_accumulation VALUES(2, 0, NULL, 0); --total
diff --git a/src/cts-addressbook.c b/src/cts-addressbook.c
new file mode 100755 (executable)
index 0000000..bb7d516
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "cts-internal.h"
+#include "cts-schema.h"
+#include "cts-sqlite.h"
+#include "cts-utils.h"
+#include "cts-addressbook.h"
+
+static inline int cts_reset_internal_addressbook(void)
+{
+       CTS_FN_CALL;
+       int ret;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       snprintf(query, sizeof(query), "DELETE FROM %s WHERE addrbook_id = %d",
+                       CTS_TABLE_CONTACTS, CTS_ADDRESSBOOK_INTERNAL);
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       snprintf(query, sizeof(query), "DELETE FROM %s WHERE addrbook_id = %d",
+                       CTS_TABLE_GROUPS, CTS_ADDRESSBOOK_INTERNAL);
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       cts_set_contact_noti();
+       cts_set_group_noti();
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_insert_addressbook(CTSvalue *addressbook)
+{
+       int ret, index;
+       cts_stmt stmt = NULL;
+       cts_addrbook *record = (cts_addrbook *)addressbook;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       retv_if(NULL == addressbook, CTS_ERR_ARG_NULL);
+       retv_if(NULL == record->name, CTS_ERR_ARG_INVALID);
+       retvm_if(CTS_VALUE_ADDRESSBOOK != record->v_type, CTS_ERR_ARG_INVALID,
+                       "addressbook is invalid type(%d)", record->v_type);
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       snprintf(query, sizeof(query),
+                       "INSERT INTO %s(addrbook_name, acc_id, acc_type, mode) "
+                       "VALUES(?, %d, %d, %d)",
+                       CTS_TABLE_ADDRESSBOOKS, record->acc_id, record->acc_type, record->mode);
+
+       stmt = cts_query_prepare(query);
+       if (NULL == stmt) {
+               ERR("cts_query_prepare() Failed");
+               contacts_svc_end_trans(false);
+               return CTS_ERR_DB_FAILED;
+       }
+
+       cts_stmt_bind_text(stmt, 1, record->name);
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       index = cts_db_get_last_insert_id();
+       cts_stmt_finalize(stmt);
+
+       cts_set_addrbook_noti();
+       ret = contacts_svc_end_trans(true);
+       retvm_if(ret < CTS_SUCCESS, ret, "contacts_svc_end_trans() Failed(%d)", ret);
+
+       return index;
+}
+
+API int contacts_svc_delete_addressbook(int addressbook_id)
+{
+       CTS_FN_CALL;
+       int ret;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       if (CTS_ADDRESSBOOK_INTERNAL == addressbook_id)
+               return cts_reset_internal_addressbook();
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       snprintf(query, sizeof(query), "DELETE FROM %s WHERE addrbook_id = %d",
+                       CTS_TABLE_ADDRESSBOOKS, addressbook_id);
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       ret = cts_db_change();
+
+       if (0 < ret) {
+               cts_set_contact_noti();
+               cts_set_group_noti();
+               cts_set_addrbook_noti();
+               ret = contacts_svc_end_trans(true);
+       }
+       else {
+               contacts_svc_end_trans(false);
+               ret = CTS_ERR_NO_DATA;
+       }
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_update_addressbook(CTSvalue *addressbook)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MIN_LEN] = {0};
+       cts_addrbook *record = (cts_addrbook *)addressbook;
+
+       retv_if(NULL == addressbook, CTS_ERR_ARG_NULL);
+       retv_if(NULL == record->name, CTS_ERR_ARG_INVALID);
+       retvm_if(CTS_VALUE_ADDRESSBOOK != record->v_type, CTS_ERR_ARG_INVALID,
+                       "addressbook is invalid type(%d)", record->v_type);
+
+       snprintf(query, sizeof(query),
+                       "UPDATE %s SET addrbook_name=?, acc_id=%d, acc_type=%d, mode=%d "
+                       "WHERE addrbook_id=%d", CTS_TABLE_ADDRESSBOOKS,
+                       record->acc_id, record->acc_type, record->mode, record->id);
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       stmt = cts_query_prepare(query);
+       if (NULL == stmt) {
+               ERR("cts_query_prepare() Failed");
+               contacts_svc_end_trans(false);
+               return CTS_ERR_DB_FAILED;
+       }
+
+       cts_stmt_bind_text(stmt, 1, record->name);
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       cts_stmt_finalize(stmt);
+
+       cts_set_addrbook_noti();
+
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_get_addressbook(int addressbook_id, CTSvalue **ret_value)
+{
+       int ret;
+       cts_addrbook *ab;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       retv_if(NULL == ret_value, CTS_ERR_ARG_NULL);
+
+       snprintf(query, sizeof(query),
+                       "SELECT addrbook_id, addrbook_name, acc_id, acc_type, mode "
+                       "FROM %s WHERE addrbook_id = %d", CTS_TABLE_ADDRESSBOOKS, addressbook_id);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret) {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_DB_RECORD_NOT_FOUND;
+       }
+
+       ab = (cts_addrbook *)contacts_svc_value_new(CTS_VALUE_ADDRESSBOOK);
+       if (ab) {
+               ab->embedded = true;
+               cts_stmt_get_addressbook(stmt, ab);
+       }
+
+       cts_stmt_finalize(stmt);
+
+       *ret_value = (CTSvalue *)ab;
+
+       return CTS_SUCCESS;
+}
diff --git a/src/cts-addressbook.h b/src/cts-addressbook.h
new file mode 100755 (executable)
index 0000000..efd64ab
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_ADDRESSBOOK_H__
+#define __CTS_ADDRESSBOOK_H__
+
+/**
+ * system addressbook id
+ */
+
+enum ADDRESSBOOK{
+       CTS_ADDRESSBOOK_INTERNAL,
+       CTS_ADDRESSBOOK_START,
+};
+
+#ifndef __CONTACTS_SVC_H__
+
+
+//<!--
+/**
+ * @defgroup   CONTACTS_SVC_ADDRESSBOOK Addressbook Modification
+ * @ingroup    CONTACTS_SVC
+ * @addtogroup CONTACTS_SVC_ADDRESSBOOK
+ * @{
+ *
+ * This interface provides methods to insert/update/delete the addressbook.
+ *
+ * - getting all addressbook (0 is logical value for internal addressbook)
+ * @code
+ void addrbook_list(void)
+ {
+        int ret, count;
+        CTSiter *iter;
+
+        count = contacts_svc_count_with_int(CTS_GET_COUNT_CONTACTS_IN_ADDRESSBOOK, 0);
+        printf("Phone(%d)", count);
+
+        ret = contacts_svc_get_list(CTS_LIST_ALL_ADDRESSBOOK, &iter);
+        if (CTS_SUCCESS != ret) {
+                printf("contacts_svc_get_list() Failed(%d)\n", ret);
+                return;
+        }
+
+        while (CTS_SUCCESS == contacts_svc_iter_next(iter)) {
+                int id;
+                const char *name;
+                CTSvalue *info;
+
+                info = contacts_svc_iter_get_info(iter);
+                id = contacts_svc_value_get_int(info, CTS_LIST_ADDRESSBOOK_ID_INT);
+                name = contacts_svc_value_get_str(info, CTS_LIST_ADDRESSBOOK_NAME_STR);
+                count = contacts_svc_count_with_int(CTS_GET_COUNT_CONTACTS_IN_ADDRESSBOOK, id);
+
+                printf("%s(%d)", name, count);
+        }
+        contacts_svc_iter_remove(iter);
+ }
+ * @endcode
+ *
+ */
+
+/**
+ * addressbook permission
+ */
+enum ADDRESSBOOKPERMISSION {
+       CTS_ADDRESSBOOK_MODE_NONE, /**< .*/
+       CTS_ADDRESSBOOK_MODE_READONLY, /**< .*/
+};
+
+/**
+ * This function inserts a addressbook information into database.
+ * The implementation assigns an index number of the addressbook automatically.
+ * \n The returned index is unique and non-reusable.
+ *
+ * @param[in] addressbook A addressbook information of #CTSvalue created by contacts_svc_value_new(CTS_VALUE_ADDRESSBOOK).
+ * @return the index of contact on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ int insert_addrbook(void)
+ {
+    int ret;
+    CTSvalue *ab;
+    ab = contacts_svc_value_new(CTS_VALUE_ADDRESSBOOK);
+
+    contacts_svc_value_set_int(ab, CTS_ADDRESSBOOK_VAL_ACC_ID_INT, 1);
+    contacts_svc_value_set_int(ab, CTS_ADDRESSBOOK_VAL_ACC_TYPE_INT, CTS_ADDRESSBOOK_TYPE_GOOGLE);
+    contacts_svc_value_set_int(ab, CTS_ADDRESSBOOK_VAL_MODE_INT, CTS_ADDRESSBOOK_MODE_NONE);
+    contacts_svc_value_set_str(ab, CTS_ADDRESSBOOK_VAL_NAME_STR, "test1");
+
+    ret = contacts_svc_insert_addressbook(ab);
+    if(ret < CTS_SUCCESS)
+       printf("contacts_svc_insert_addressbook() Failed\n");
+
+    contacts_svc_value_free(ab);
+    return ret;
+ }
+ * @endcode
+ */
+int contacts_svc_insert_addressbook(CTSvalue *addressbook);
+
+/**
+ * This function deletes the addressbook information related to addressbook_id.
+ * Also, the related contacts and groups are deleted.
+ * @param[in] addressbook_id index of addressbook
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_delete_addressbook(int addressbook_id);
+
+/**
+ * This function updates a addressbook information into database.
+ *
+ * @param[in] addressbook A addressbook information of #CTSvalue created by contacts_svc_get_addressbook().
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void update_addrbook(void)
+ {
+    int ret;
+    CTSvalue *ab = NULL;
+    ret = contacts_svc_get_addressbook(2, &ab);
+    if(CTS_SUCCESS != ret) {
+       printf("contacts_svc_get_addressbook() Failed\n");
+       return;
+    }
+
+    contacts_svc_value_set_str(ab, CTS_ADDRESSBOOK_VAL_NAME_STR,"Fixed-addressbook");
+
+    ret = contacts_svc_update_addressbook(ab);
+    if(ret < CTS_SUCCESS)
+       printf("contacts_svc_update_addressbook() Failed\n");
+
+    contacts_svc_value_free(ab);
+ }
+ * @endcode
+ */
+int contacts_svc_update_addressbook(CTSvalue *addressbook);
+
+/**
+ * This function gets a addressbook record which has the index from the database.
+ * Obtained addressbook record should be free using by contacts_svc_value_free().
+ * @param[in] addressbook_id The index of addressbook to get
+ * @param[out] ret_value Points of the addressbook record which is returned
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void get_addrbook(int addressbook_id)
+ {
+    int ret;
+    const char *name;
+    CTSvalue *ab = NULL;
+
+    ret = contacts_svc_get_addressbook(addressbook_id, &ab);
+    if(CTS_SUCCESS != ret) {
+       printf("contacts_svc_get_addressbook() Failed\n");
+       return;
+    }
+
+    printf("///////////%d//////////////\n",
+          contacts_svc_value_get_int(ab, CTS_ADDRESSBOOK_VAL_ID_INT));
+    printf("The related account ID : %d\n",
+          contacts_svc_value_get_int(ab, CTS_ADDRESSBOOK_VAL_ACC_ID_INT));
+    printf("The related account type : %d\n",
+          contacts_svc_value_get_int(ab, CTS_ADDRESSBOOK_VAL_ACC_TYPE_INT));
+    printf("permission : %d\n",
+          contacts_svc_value_get_int(ab, CTS_ADDRESSBOOK_VAL_MODE_INT));
+
+    name = contacts_svc_value_get_str(ab, CTS_ADDRESSBOOK_VAL_NAME_STR);
+    if(name)
+       printf("Name : %s\n", name);
+    printf("//////////////////////////\n");
+
+   contacts_svc_value_free(ab);
+ }
+ * @endcode
+ */
+int contacts_svc_get_addressbook(int addressbook_id, CTSvalue **ret_value);
+
+/**
+ * @}
+ */
+//-->
+#endif //__CONTACTS_SVC_H__
+#endif //__CTS_ADDRESSBOOK_H__
diff --git a/src/cts-contact.c b/src/cts-contact.c
new file mode 100755 (executable)
index 0000000..b090565
--- /dev/null
@@ -0,0 +1,3160 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <time.h>
+
+#include "cts-internal.h"
+#include "cts-schema.h"
+#include "cts-sqlite.h"
+#include "cts-utils.h"
+#include "cts-group.h"
+#include "cts-types.h"
+#include "cts-normalize.h"
+#include "cts-contact.h"
+
+static const int CTS_UPDATE_ID_LOC = 11;
+
+static inline int cts_insert_contact_data_number(cts_stmt stmt,
+               GSList* number_list)
+{
+       CTS_FN_CALL;
+
+       int ret, cnt, default_num=0, mobile_num=0;
+       GSList *number_repeat = number_list;
+       cts_number *number_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == number_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (number_data = (cts_number *)number_repeat->data)
+                               && !number_data->deleted && number_data->number)
+               {
+                       const char *normal_num;
+                       char clean_num[CTS_NUMBER_MAX_LEN];
+
+                       cnt = 1;
+                       cts_stmt_bind_int(stmt, cnt++, CTS_DATA_NUMBER);
+                       cts_stmt_bind_int(stmt, cnt++, number_data->type);
+                       ret = cts_clean_number(number_data->number, clean_num, sizeof(clean_num));
+                       if (ret <= 0) {
+                               ERR("Number(%s) is invalid", number_data->number);
+                               number_repeat = g_slist_next(number_repeat);
+                               continue;
+                       }
+
+                       cts_stmt_bind_text(stmt, cnt++, clean_num);
+                       normal_num = cts_normalize_number(clean_num);
+                       cts_stmt_bind_text(stmt, cnt++, normal_num);
+
+                       ret = cts_stmt_step(stmt);
+                       retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                       number_data->id = cts_db_get_last_insert_id();
+
+                       if (number_data->is_default)
+                               default_num = number_data->id;
+                       else if (!default_num && CTS_NUM_TYPE_CELL & number_data->type && !mobile_num)
+                               mobile_num = number_data->id;
+                       cts_stmt_reset(stmt);
+               }
+               number_repeat = g_slist_next(number_repeat);
+       }while(number_repeat);
+
+       if (default_num)
+               return default_num;
+       else
+               return mobile_num;
+}
+
+static inline int cts_insert_contact_data_email(cts_stmt stmt,
+               GSList* email_list)
+{
+       CTS_FN_CALL;
+
+       int ret, cnt, default_email=0;
+       GSList *email_repeat = email_list;
+       cts_email *email_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == email_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (email_data = (cts_email *)email_repeat->data)
+                               && !email_data->deleted && email_data->email_addr)
+               {
+                       cnt = 1;
+                       cts_stmt_bind_int(stmt, cnt++, CTS_DATA_EMAIL);
+                       cts_stmt_bind_int(stmt, cnt++, email_data->type);
+                       cts_stmt_bind_text(stmt, cnt++, email_data->email_addr);
+
+                       ret = cts_stmt_step(stmt);
+                       retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                       email_data->id = cts_db_get_last_insert_id();
+
+                       if (email_data->is_default)
+                               default_email = email_data->id;
+                       cts_stmt_reset(stmt);
+               }
+               email_repeat = g_slist_next(email_repeat);
+       }while(email_repeat);
+
+       return default_email;
+}
+
+static inline int cts_insert_contact_grouprel(int acc_id, int index,
+               GSList* group_list)
+{
+       CTS_FN_CALL;
+
+       GSList *group_repeat = group_list;
+       cts_group *group_data;
+
+       retv_if(NULL == group_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               group_data = group_repeat->data;
+               group_repeat = group_repeat->next;
+
+               if (NULL == group_data || group_data->deleted)
+                       continue;
+
+               if (group_data->vcard_group) {
+                       int found_id;
+                       found_id = contacts_svc_find_group(acc_id, group_data->vcard_group);
+                       if (0 < found_id)
+                               group_data->id = found_id;
+                       else if (found_id == CTS_ERR_DB_RECORD_NOT_FOUND) {
+                               CTSvalue *group;
+                               group = contacts_svc_value_new(CTS_VALUE_GROUP);
+
+                               contacts_svc_value_set_str(group, CTS_GROUP_VAL_NAME_STR, group_data->vcard_group);
+                               found_id = contacts_svc_insert_group(acc_id, group);
+                               if (found_id < CTS_SUCCESS)
+                                       ERR("contacts_svc_insert_group() Failed\n");
+                               else
+                                       group_data->id = found_id;
+
+                               contacts_svc_value_free(group);
+                       }
+               }
+               if (group_data->id) {
+                       int ret = cts_group_set_relation(group_data->id, index, acc_id);
+                       retvm_if(ret < CTS_SUCCESS, ret, "cts_group_set_relation() Failed(%d)", ret);
+               }
+       }while(group_repeat);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_insert_contact_data_event(cts_stmt stmt,
+               GSList* event_list)
+{
+       CTS_FN_CALL;
+
+       GSList *event_repeat = event_list;
+       cts_event *event_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == event_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (event_data = (cts_event *)event_repeat->data)
+                               && !event_data->deleted && event_data->date)
+               {
+                       cts_stmt_bind_int(stmt, 1, CTS_DATA_EVENT);
+                       cts_stmt_bind_event(stmt, 2, event_data);
+
+                       int ret = cts_stmt_step(stmt);
+                       retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                       cts_stmt_reset(stmt);
+               }
+               event_repeat = g_slist_next(event_repeat);
+       }while(event_repeat);
+
+       return CTS_SUCCESS;
+}
+
+
+static inline int cts_insert_contact_data_messenger(cts_stmt stmt,
+               GSList* messenger_list)
+{
+       CTS_FN_CALL;
+
+       GSList *messenger_repeat = messenger_list;
+       cts_messenger *messenger_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == messenger_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (messenger_data = (cts_messenger *)messenger_repeat->data)
+                               && !messenger_data->deleted && messenger_data->im_id)
+               {
+                       cts_stmt_bind_int(stmt, 1, CTS_DATA_MESSENGER);
+                       cts_stmt_bind_messenger(stmt, 2, messenger_data);
+
+                       int ret = cts_stmt_step(stmt);
+                       retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                       cts_stmt_reset(stmt);
+               }
+               messenger_repeat = g_slist_next(messenger_repeat);
+       }while(messenger_repeat);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_insert_contact_data_postal(cts_stmt stmt,
+               GSList* postal_list)
+{
+       CTS_FN_CALL;
+
+       GSList *postal_repeat = postal_list;
+       cts_postal *postal_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == postal_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (postal_data = (cts_postal *)postal_repeat->data)
+                               && !postal_data->deleted
+                               && (postal_data->country || postal_data->pobox
+                                       || postal_data->postalcode || postal_data->region
+                                       || postal_data->locality || postal_data->street || postal_data->extended))
+               {
+                       cts_stmt_bind_int(stmt, 1, CTS_DATA_POSTAL);
+                       cts_stmt_bind_postal(stmt, 2, postal_data);
+
+                       int ret = cts_stmt_step(stmt);
+                       retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                       cts_stmt_reset(stmt);
+               }
+               postal_repeat = g_slist_next(postal_repeat);
+       }while(postal_repeat);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_insert_contact_data_web(cts_stmt stmt,
+               GSList* web_list)
+{
+       CTS_FN_CALL;
+
+       GSList *web_repeat = web_list;
+       cts_web *web_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == web_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (web_data = (cts_web *)web_repeat->data)
+                               && !web_data->deleted && web_data->url)
+               {
+                       cts_stmt_bind_int(stmt, 1, CTS_DATA_WEB);
+                       cts_stmt_bind_web(stmt, 2, web_data);
+
+                       int ret = cts_stmt_step(stmt);
+                       retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                       cts_stmt_reset(stmt);
+               }
+               web_repeat = g_slist_next(web_repeat);
+       }while(web_repeat);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_insert_contact_data_nick(cts_stmt stmt,
+               GSList* nick_list)
+{
+       CTS_FN_CALL;
+       GSList *nick_repeat = nick_list;
+       cts_nickname *nick_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == nick_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (nick_data = (cts_nickname *)nick_repeat->data)
+                               && !nick_data->deleted && nick_data->nick)
+               {
+                       cts_stmt_bind_int(stmt, 1, CTS_DATA_NICKNAME);
+                       cts_stmt_bind_text(stmt, 3, nick_data->nick);
+
+                       int ret = cts_stmt_step(stmt);
+                       retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                       cts_stmt_reset(stmt);
+               }
+               nick_repeat = g_slist_next(nick_repeat);
+       }while(nick_repeat);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_insert_contact_data_extend(cts_stmt stmt,
+               GSList* extend_list)
+{
+       CTS_FN_CALL;
+
+       GSList *extend_repeat = extend_list;
+       cts_extend *extend_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == extend_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (extend_data = (cts_extend *)extend_repeat->data)
+                               && !extend_data->deleted)
+               {
+                       cts_stmt_bind_int(stmt, 1, extend_data->type);
+                       cts_stmt_bind_extend(stmt, 2, extend_data);
+
+                       int ret = cts_stmt_step(stmt);
+                       retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                       cts_stmt_reset(stmt);
+               }
+               extend_repeat = g_slist_next(extend_repeat);
+       }while(extend_repeat);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_make_name_lookup(int op_code, cts_name *name,
+               char *name_lookup, int name_lookup_size)
+{
+       if (name->display) {
+               snprintf(name_lookup, name_lookup_size, "%s", name->display);
+               return CTS_SUCCESS;
+       }
+
+       if (CTS_ORDER_NAME_FIRSTLAST == op_code)
+               snprintf(name_lookup, name_lookup_size, "%s %c%s",
+                               SAFE_STR(name->first), 0x1, SAFE_STR(name->last));
+       else
+               snprintf(name_lookup, name_lookup_size, "%s,%c %c%s",
+                               SAFE_STR(name->last), 0x1, 0x1, SAFE_STR(name->first));
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_insert_contact_data_name(cts_stmt stmt,
+               cts_name *name)
+{
+       int ret;
+       int cnt = 2;
+       cts_name normalize_name={0};
+       char *tmp_display, *tmp_first, *tmp_last;
+       char display[CTS_SQL_MAX_LEN]={0};
+       char lookup[CTS_SQL_MAX_LEN]={0};
+       char reverse_lookup[CTS_SQL_MAX_LEN]={0};
+
+       //insert name search info
+       char normal_name[CTS_NN_MAX][CTS_SQL_MAX_LEN]={{0},{0},{0}};
+
+       tmp_display = name->display;
+       tmp_first = name->first;
+       tmp_last = name->last;
+
+       if (name->display) {
+               ret = cts_normalize_name(name, normal_name, true);
+               retvm_if(ret < CTS_SUCCESS, ret, "cts_normalize_name() Failed(%d)", ret);
+               if (normal_name[CTS_NN_FIRST][0])
+                       normalize_name.display = normal_name[CTS_NN_FIRST];
+               else
+                       name->display = NULL;
+       }
+
+       if (NULL == name->display) {
+               ret = cts_normalize_name(name, normal_name, false);
+               retvm_if(ret < CTS_SUCCESS, ret, "cts_normalize_name() Failed(%d)", ret);
+
+               switch (ret)
+               {
+               case CTS_LANG_KOREAN:
+                       snprintf(display, sizeof(display), "%s%s",
+                                       SAFE_STR(name->last), SAFE_STR(name->first));
+
+                       strncat(normal_name[CTS_NN_LAST], normal_name[CTS_NN_FIRST],
+                                       sizeof(normal_name[CTS_NN_LAST]));
+
+                       name->display = display;
+                       normalize_name.display = normal_name[CTS_NN_LAST];
+                       break;
+               case CTS_LANG_ENGLISH:
+               default:
+                       if (normal_name[CTS_NN_FIRST][0])
+                               normalize_name.first = normal_name[CTS_NN_FIRST];
+                       else
+                               name->first = NULL;
+
+                       if (normal_name[CTS_NN_LAST][0])
+                               normalize_name.last = normal_name[CTS_NN_LAST];
+                       else
+                               name->last = NULL;
+
+                       break;
+               }
+       }
+
+       if (cts_get_default_language() == ret)
+               cts_stmt_bind_int(stmt, cnt, CTS_LANG_DEFAULT);
+       else
+               cts_stmt_bind_int(stmt, cnt, ret);
+       cnt = cts_stmt_bind_name(stmt, cnt, name);
+
+       name->display = tmp_display;
+       name->first = tmp_first;
+       name->last = tmp_last;
+
+       ret = cts_make_name_lookup(CTS_ORDER_NAME_FIRSTLAST, &normalize_name,
+                                                                               lookup, sizeof(lookup));
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_make_name_lookup() Failed(%d)", ret);
+
+       ret = cts_make_name_lookup(CTS_ORDER_NAME_LASTFIRST, &normalize_name,
+                                                                               reverse_lookup, sizeof(reverse_lookup));
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_make_name_lookup() Failed(%d)", ret);
+
+       CTS_DBG("lookup=%s(%d), reverse_lookup=%s(%d)",
+                       lookup, strlen(lookup), reverse_lookup, strlen(reverse_lookup));
+
+       cts_stmt_bind_text(stmt, cnt++, lookup);
+       cts_stmt_bind_text(stmt, cnt++, reverse_lookup);
+       cts_stmt_bind_text(stmt, cnt++, normal_name[CTS_NN_SORTKEY]);
+
+       return cnt;
+}
+
+static int cts_insert_contact_data(int field, contact_t *contact)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       snprintf(query, sizeof(query), "INSERT INTO %s(contact_id, datatype, "
+                       "data1, data2, data3, data4, data5, data6, data7, data8, data9, data10) "
+                       "VALUES(%d, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+                       CTS_TABLE_DATA, contact->base->id);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       //Insert the name
+       if ((field & CTS_DATA_FIELD_NAME))
+       {
+               cts_stmt_bind_int(stmt, 1, CTS_DATA_NAME);
+
+               if (contact->name) {
+                       ret = cts_insert_contact_data_name(stmt, contact->name);
+                       if (ret < CTS_SUCCESS)
+                       {
+                               ERR("cts_insert_contact_data_name() Failed(%d)", ret);
+                               cts_stmt_finalize(stmt);
+                               return ret;
+                       }
+               }
+
+               ret = cts_stmt_step(stmt);
+               if (CTS_SUCCESS != ret) {
+                       ERR("cts_stmt_step() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+               cts_stmt_reset(stmt);
+       }
+
+       //Insert the company
+       if (contact->company && (field & CTS_DATA_FIELD_COMPANY))
+       {
+               cts_company *com = contact->company;
+               if (com->name || com->department || com->jot_title || com->role || com->assistant_name) {
+                       cts_stmt_bind_int(stmt, 1, CTS_DATA_COMPANY);
+                       cts_stmt_bind_company(stmt, 2, com);
+
+                       ret = cts_stmt_step(stmt);
+                       if (CTS_SUCCESS != ret) {
+                               ERR("cts_stmt_step() Failed(%d)", ret);
+                               cts_stmt_finalize(stmt);
+                               return ret;
+                       }
+                       cts_stmt_reset(stmt);
+               }
+       }
+
+       //Insert the events
+       if (contact->events && (field & CTS_DATA_FIELD_EVENT))
+       {
+               ret = cts_insert_contact_data_event(stmt, contact->events);
+
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_insert_contact_data_event() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+       }
+
+       //Insert the messengers
+       if (contact->messengers && (field & CTS_DATA_FIELD_MESSENGER))
+       {
+               ret = cts_insert_contact_data_messenger(stmt, contact->messengers);
+
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_insert_contact_data_messenger() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+       }
+
+       //Insert the postals
+       if (contact->postal_addrs && (field & CTS_DATA_FIELD_POSTAL))
+       {
+               ret = cts_insert_contact_data_postal(stmt, contact->postal_addrs);
+
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_insert_contact_data_postal() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+       }
+
+       //Insert the Web addrs
+       if (contact->web_addrs && (field & CTS_DATA_FIELD_WEB))
+       {
+               ret = cts_insert_contact_data_web(stmt, contact->web_addrs);
+
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_insert_contact_data_web() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+       }
+
+       //Insert the Nick names
+       if (contact->nicknames && (field & CTS_DATA_FIELD_NICKNAME))
+       {
+               ret = cts_insert_contact_data_nick(stmt, contact->nicknames);
+
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_insert_contact_data_nick() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+       }
+
+       //Insert the numbers
+       if (contact->numbers && (field & CTS_DATA_FIELD_NUMBER))
+       {
+               ret = cts_insert_contact_data_number(stmt, contact->numbers);
+
+               if (ret < CTS_SUCCESS)
+               {
+                       ERR("cts_insert_contact_data_number() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+               contact->default_num = ret;
+       }
+
+       //Insert the emails
+       if (contact->emails && (field & CTS_DATA_FIELD_EMAIL))
+       {
+               ret = cts_insert_contact_data_email(stmt, contact->emails);
+
+               if (ret < CTS_SUCCESS) {
+                       ERR("cts_insert_contact_data_email() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+               contact->default_email = ret;
+       }
+
+
+       //Insert the extended values
+       if (contact->extended_values && (field & CTS_DATA_FIELD_EXTEND_ALL))
+       {
+               ret = cts_insert_contact_data_extend(stmt, contact->extended_values);
+
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_insert_contact_data_extend() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+       }
+
+       cts_stmt_finalize(stmt);
+
+       return CTS_SUCCESS;
+}
+
+static int cts_set_first_id_for_default(contact_t *contact)
+{
+       GSList *cur;
+
+       if (!contact->default_num)
+       {
+               for (cur = contact->numbers;cur;cur = cur->next) {
+                       if(cur->data) {
+                               cts_number *num = cur->data;
+                               if(!num->deleted && num->id) {
+                                       contact->default_num = num->id;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       if (!contact->default_email)
+       {
+               for (cur = contact->emails;cur;cur = cur->next) {
+                       if(cur->data) {
+                               cts_email *email = cur->data;
+                               if(!email->deleted && email->id) {
+                                       contact->default_email = email->id;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       return CTS_SUCCESS;
+}
+
+static inline char* cts_contact_get_valid_first_number_or_email(GSList *numbers, GSList *emails)
+{
+       GSList *cur;
+
+       for (cur=numbers;cur;cur=cur->next) {
+               cts_number *num = cur->data;
+               if (num && !num->deleted && num->number) {
+                       return num->number;
+               }
+       }
+
+       for (cur=emails;cur;cur=cur->next) {
+               cts_email *email = cur->data;
+               if (email && !email->deleted && email->email_addr) {
+                       return email->email_addr;
+               }
+       }
+       return NULL;
+}
+
+static inline void cts_insert_contact_handle_no_name(contact_t *contact)
+{
+       if (NULL == contact->name) {
+               contact->name = calloc(1, sizeof(cts_name));
+               contact->name->embedded = true;
+       }
+
+       if (contact->name->display || contact->name->first || contact->name->last)
+               return;
+
+       if (contact->company && contact->company->name)
+               contact->name->display = strdup(contact->company->name);
+       else {
+               char *temp;
+
+               temp = cts_contact_get_valid_first_number_or_email(contact->numbers, contact->emails);
+               contact->name->display = SAFE_STRDUP(temp);
+       }
+       return;
+}
+
+static inline int cts_safe_strcmp(char *s1, char *s2)
+{
+       if (NULL == s1 || NULL == s2)
+               return !(s1 == s2);
+       else
+               return strcmp(s1, s2);
+}
+
+
+static inline void cts_contact_remove_dup_data_number(GSList *numbers)
+{
+       GSList *cur1, *cur2;
+
+       cts_number *num1, *num2;
+       for (cur1=numbers;cur1;cur1=cur1->next) {
+               num1 = cur1->data;
+               if (NULL == num1 || num1->deleted)
+                       continue;
+               for (cur2=numbers;cur2;cur2=cur2->next) {
+                       num2 = cur2->data;
+                       if(NULL == num2 || num1 == num2)
+                               continue;
+                       if (!num2->deleted && num1->type == num2->type &&
+                                       !cts_safe_strcmp(num1->number, num2->number)) {
+                               num1->is_default |= num2->is_default;
+                               num1->is_favorite |= num2->is_favorite;
+                               num2->deleted = true;
+                       }
+               }
+       }
+}
+
+
+static inline void cts_contact_remove_dup_data_email(GSList *emails)
+{
+       GSList *cur1, *cur2;
+       cts_email *email1, *email2;
+
+       for (cur1=emails;cur1;cur1=cur1->next) {
+               email1 = cur1->data;
+               if (NULL == email1 || email1->deleted)
+                       continue;
+               for (cur2=emails;cur2;cur2=cur2->next) {
+                       email2 = cur2->data;
+                       if(NULL == email2 || email1 == email2)
+                               continue;
+                       if (!email2->deleted && email1->type == email2->type &&
+                                       !cts_safe_strcmp(email1->email_addr, email2->email_addr)) {
+                               email1->is_default |= email2->is_default;
+                               email2->deleted = true;
+                       }
+               }
+       }
+}
+
+static inline void cts_contact_remove_dup_data_event(GSList *events)
+{
+       GSList *cur1, *cur2;
+       cts_event *event1, *event2;
+
+       for (cur1=events;cur1;cur1=cur1->next) {
+               event1 = cur1->data;
+               if (NULL == event1 || event1->deleted)
+                       continue;
+               for (cur2=events;cur2;cur2=cur2->next) {
+                       event2 = cur2->data;
+                       if(NULL == event2 || event1 == event2)
+                               continue;
+                       if (!event2->deleted && event1->type == event2->type &&
+                                       event1->date == event2->date) {
+                               event2->deleted = true;
+                       }
+               }
+       }
+}
+
+
+static inline void cts_contact_remove_dup_data_IM(GSList *IMs)
+{
+       GSList *cur1, *cur2;
+       cts_messenger *im1, *im2;
+
+       for (cur1=IMs;cur1;cur1=cur1->next) {
+               im1 = cur1->data;
+               if (NULL == im1 || im1->deleted)
+                       continue;
+               for (cur2=IMs;cur2;cur2=cur2->next) {
+                       im2 = cur2->data;
+                       if(NULL == im2 || im1 == im2)
+                               continue;
+                       if (!im2->deleted && im1->type == im2->type &&
+                                       !cts_safe_strcmp(im1->im_id, im2->im_id)) {
+                               im2->deleted = true;
+                       }
+               }
+       }
+}
+
+
+static inline void cts_contact_remove_dup_data_web(GSList *webs)
+{
+       GSList *cur1, *cur2;
+       cts_web *web1, *web2;
+
+       for (cur1=webs;cur1;cur1=cur1->next) {
+               web1 = cur1->data;
+               if (NULL == web1 || web1->deleted)
+                       continue;
+               for (cur2=webs;cur2;cur2=cur2->next) {
+                       web2 = cur2->data;
+                       if(NULL == web2 || web1 == web2)
+                               continue;
+                       if (!web2->deleted && web1->type == web2->type &&
+                                       !cts_safe_strcmp(web1->url, web2->url)) {
+                               web2->deleted = true;
+                       }
+               }
+       }
+}
+
+
+static inline void cts_contact_remove_dup_data_nick(GSList *nicks)
+{
+       GSList *cur1, *cur2;
+       cts_nickname *nick1, *nick2;
+
+       for (cur1=nicks;cur1;cur1=cur1->next) {
+               nick1 = cur1->data;
+               if (NULL == nick1 || nick1->deleted)
+                       continue;
+               for (cur2=nicks;cur2;cur2=cur2->next) {
+                       nick2 = cur2->data;
+                       if(NULL == nick2 || nick1 == nick2)
+                               continue;
+                       if (!nick2->deleted && !cts_safe_strcmp(nick1->nick, nick2->nick)) {
+                               nick2->deleted = true;
+                       }
+               }
+       }
+}
+
+
+static inline void cts_contact_remove_dup_data_postal(GSList *postals)
+{
+       GSList *cur1, *cur2;
+       cts_postal *addr1, *addr2;
+
+       for (cur1=postals;cur1;cur1=cur1->next) {
+               addr1 = cur1->data;
+               if (NULL == addr1 || addr1->deleted)
+                       continue;
+               for (cur2=postals;cur2;cur2=cur2->next) {
+                       addr2 = cur2->data;
+                       if(NULL == addr2 || addr1 == addr2)
+                               continue;
+                       if (!addr2->deleted && addr1->type == addr2->type &&
+                                       !cts_safe_strcmp(addr1->pobox, addr2->pobox) &&
+                                       !cts_safe_strcmp(addr1->postalcode, addr2->postalcode) &&
+                                       !cts_safe_strcmp(addr1->region, addr2->region) &&
+                                       !cts_safe_strcmp(addr1->locality, addr2->locality) &&
+                                       !cts_safe_strcmp(addr1->street, addr2->street) &&
+                                       !cts_safe_strcmp(addr1->extended, addr2->extended) &&
+                                       !cts_safe_strcmp(addr1->country, addr2->country)) {
+                               addr2->deleted = true;
+                       }
+               }
+       }
+}
+
+
+static void cts_contact_remove_dup_data(contact_t *contact)
+{
+       if (contact->numbers)
+               cts_contact_remove_dup_data_number(contact->numbers);
+
+       if (contact->emails)
+               cts_contact_remove_dup_data_email(contact->emails);
+
+       if (contact->events)
+               cts_contact_remove_dup_data_event(contact->events);
+
+       if (contact->messengers)
+               cts_contact_remove_dup_data_IM(contact->messengers);
+
+       if (contact->web_addrs)
+               cts_contact_remove_dup_data_web(contact->web_addrs);
+
+       if (contact->nicknames)
+               cts_contact_remove_dup_data_nick(contact->nicknames);
+
+       if (contact->postal_addrs)
+               cts_contact_remove_dup_data_postal(contact->postal_addrs);
+
+}
+
+static inline int cts_insert_contact(int addressbook_id, contact_t *contact)
+{
+       int ret;
+       char *img_path;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       retv_if(NULL == contact, CTS_ERR_ARG_NULL);
+
+       cts_insert_contact_handle_no_name(contact);
+       cts_contact_remove_dup_data(contact);
+
+       //Insert Data
+       ret = cts_insert_contact_data(CTS_DATA_FIELD_ALL, contact);
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_insert_contact_data() Failed(%d)", ret);
+
+       //Insert group Info
+       if (contact->grouprelations)
+       {
+               ret = cts_insert_contact_grouprel(addressbook_id, contact->base->id,
+                               contact->grouprelations);
+               retvm_if(ret < CTS_SUCCESS, ret, "cts_insert_contact_grouprel() Failed(%d)", ret);
+       }
+
+       // default setting
+       if (!contact->default_num || !contact->default_email)
+               ret = cts_set_first_id_for_default(contact);
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_set_first_id_for_default() Failed(%d)", ret);
+
+       //insert contact table
+       int input_ver = cts_get_next_ver();
+
+       snprintf(query, sizeof(query),
+                       "INSERT INTO %s(contact_id, addrbook_id, created_ver, changed_ver, "
+                       "changed_time, default_num, default_email, uid, ringtone, note, image0, image1) "
+                       "VALUES(%d, %d, %d, %d, %d, %d, %d, ?, ?, ?, ?, ?)",
+                       CTS_TABLE_CONTACTS, contact->base->id, addressbook_id, input_ver,
+                       input_ver, (int)time(NULL), contact->default_num, contact->default_email);
+
+       cts_stmt stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       if (contact->base->uid)
+               cts_stmt_bind_text(stmt, 1, contact->base->uid);
+       if (contact->base->ringtone_path)
+               cts_stmt_bind_text(stmt, 2, contact->base->ringtone_path);
+       if (contact->base->note)
+               cts_stmt_bind_text(stmt, 3, contact->base->note);
+
+       if (contact->base->img_path) {
+               ret = cts_add_image_file(CTS_IMG_NORMAL, contact->base->id, contact->base->img_path, &img_path);
+               if (CTS_SUCCESS != ret) {
+                       ERR("cts_add_image_file(NORMAL) Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+               cts_stmt_bind_text(stmt, 4, img_path);
+       }
+       else if (contact->base->vcard_img_path) {
+               ret = cts_add_image_file(CTS_IMG_NORMAL, contact->base->id, contact->base->vcard_img_path, &img_path);
+               if (CTS_SUCCESS == ret)
+                       cts_stmt_bind_text(stmt, 4, img_path);
+       }
+
+       ret = cts_add_image_file(CTS_IMG_FULL, contact->base->id, contact->base->full_img_path, &img_path);
+       if (CTS_SUCCESS == ret)
+               cts_stmt_bind_text(stmt, 5, img_path);
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return ret;
+       }
+       cts_stmt_finalize(stmt);
+
+       return CTS_SUCCESS;
+}
+
+
+API int contacts_svc_insert_contact(int addressbook_id, CTSstruct* contact)
+{
+       int ret;
+       contact_t *record;
+
+       CTS_FN_CALL;
+
+       retv_if(NULL == contact, CTS_ERR_ARG_NULL);
+       retvm_if(CTS_STRUCT_CONTACT != contact->s_type, CTS_ERR_ARG_INVALID,
+                       "The contact(%d) must be type of CTS_STRUCT_CONTACT.", contact->s_type);
+
+       CTS_START_TIME_CHECK;
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       record = (contact_t *)contact;
+
+       ret = cts_db_get_next_id(CTS_TABLE_CONTACTS);
+       if (ret < CTS_SUCCESS)
+       {
+               ERR("cts_db_get_next_id() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       CTS_DBG("index = %d.", ret);
+
+       if (!record->base) {
+               record->base = (cts_ct_base*)contacts_svc_value_new(CTS_VALUE_CONTACT_BASE_INFO);
+
+               if (NULL == record->base)
+               {
+                       ERR("contacts_svc_value_new() Failed");
+                       contacts_svc_end_trans(false);
+                       return CTS_ERR_OUT_OF_MEMORY;
+               }
+       }
+
+       record->base->id = ret;
+       record->base->addrbook_id = addressbook_id;
+       ret = cts_insert_contact(addressbook_id, record);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_insert_contact() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       cts_set_contact_noti();
+       ret = contacts_svc_end_trans(true);
+       retvm_if(ret < CTS_SUCCESS, ret, "contacts_svc_end_trans() Failed(%d)", ret);
+
+       CTS_END_TIME_CHECK();
+       return record->base->id;
+}
+
+API int contacts_svc_delete_contact(int index)
+{
+       CTS_FN_CALL;
+       int ret, addrbook_id;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       CTS_START_TIME_CHECK;
+
+       snprintf(query, sizeof(query),
+                       "SELECT addrbook_id FROM %s WHERE contact_id = %d",
+                       CTS_TABLE_CONTACTS, index);
+       addrbook_id = cts_query_get_first_int_result(query);
+       retvm_if(addrbook_id < CTS_SUCCESS, addrbook_id,
+                       "The index(%d) is Invalid(%d)", index, addrbook_id);
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       ret = cts_delete_image_file(CTS_IMG_NORMAL, index);
+       if (CTS_SUCCESS != ret && CTS_ERR_DB_RECORD_NOT_FOUND != ret) {
+               ERR("cts_delete_image_file(NORMAL) Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       ret = cts_delete_image_file(CTS_IMG_FULL, index);
+       warn_if(CTS_SUCCESS != ret && CTS_ERR_DB_RECORD_NOT_FOUND != ret,
+                       "cts_delete_image_file(FULL) Failed(%d)", ret);
+
+       snprintf(query, sizeof(query), "DELETE FROM %s WHERE contact_id = %d",
+                       CTS_TABLE_CONTACTS, index);
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       snprintf(query, sizeof(query), "INSERT INTO %s VALUES(%d, %d, %d)",
+                       CTS_TABLE_DELETEDS, index, addrbook_id, cts_get_next_ver());
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       cts_set_contact_noti();
+
+       ret = contacts_svc_end_trans(true);
+       CTS_END_TIME_CHECK();
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+static inline int cts_delete_record_by_id(const char *table, int id)
+{
+       int ret;
+       char query[CTS_SQL_MIN_LEN] = {0};
+
+       retv_if(NULL == table, CTS_ERR_ARG_NULL);
+
+       snprintf(query, sizeof(query), "DELETE FROM %s WHERE id=%d", table, id);
+
+       ret = cts_query_exec(query);
+       retvm_if(ret, ret, "cts_query_exec() Failed(%d)", ret);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_update_contact_data_number(
+               cts_stmt stmt, int contact_id, GSList* number_list)
+{
+       CTS_FN_CALL;
+
+       int ret, default_num=0, mobile_num=0;
+       GSList *added_numbers=NULL, *number_repeat = number_list;
+       cts_number *number_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == number_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (number_data = (cts_number *)number_repeat->data))
+               {
+                       if (!number_data->id){
+                               if (!number_data->deleted)
+                                       added_numbers = g_slist_append(added_numbers, number_data);
+                               number_repeat = g_slist_next(number_repeat);
+                               continue;
+                       }
+                       if (number_data->deleted || NULL == number_data->number) {
+                               ret = cts_delete_record_by_id(CTS_TABLE_DATA, number_data->id);
+                               retvm_if(ret, ret, "cts_delete_record_by_id() Failed(%d)", ret);
+                       }
+                       else
+                       {
+                               int cnt = 1;
+                               const char *normal_num;
+                               char clean_num[CTS_NUMBER_MAX_LEN];
+
+                               cts_stmt_bind_int(stmt, cnt++, number_data->type);
+
+                               ret = cts_clean_number(number_data->number, clean_num, sizeof(clean_num));
+                               if (ret <= 0) {
+                                       ERR("Number(%s) is invalid", number_data->number);
+                                       number_repeat = g_slist_next(number_repeat);
+                                       continue;
+                               }
+                               cts_stmt_bind_text(stmt, cnt++, clean_num);
+
+                               normal_num = cts_normalize_number(clean_num);
+                               cts_stmt_bind_text(stmt, cnt++, normal_num);
+                               cts_stmt_bind_int(stmt, CTS_UPDATE_ID_LOC, number_data->id);
+
+                               ret = cts_stmt_step(stmt);
+                               retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+
+                               if (number_data->is_default)
+                                       default_num = number_data->id;
+                               else if (!default_num && CTS_NUM_TYPE_CELL & number_data->type && !mobile_num)
+                                       mobile_num = number_data->id;
+                               cts_stmt_reset(stmt);
+                       }
+               }
+               number_repeat = g_slist_next(number_repeat);
+       }while(number_repeat);
+
+       if (added_numbers) {
+               contact_t temp;
+               cts_ct_base base;
+               temp.base = &base;
+               temp.base->id = contact_id;
+               temp.numbers = added_numbers;
+
+               ret = cts_insert_contact_data(CTS_DATA_FIELD_NUMBER, &temp);
+               if (temp.default_num) {
+                       number_repeat = added_numbers;
+                       while (number_repeat) {
+                               if (NULL != (number_data = (cts_number *)number_repeat->data)) {
+                                       if (number_data->is_default) {
+                                               default_num = temp.default_num;
+                                               break;
+                                       }
+                               }
+                               number_repeat = number_repeat->next;
+                       }
+                       if(!default_num)
+                               mobile_num = temp.default_num;
+               }
+               g_slist_free(added_numbers);
+               retvm_if(CTS_SUCCESS != ret, ret, "cts_insert_contact_data() Failed(%d)", ret);
+       }
+
+       if (default_num)
+               return default_num;
+       else
+               return mobile_num;
+}
+
+static inline int cts_update_contact_data_email(
+               cts_stmt stmt, int contact_id, GSList* email_list)
+{
+       CTS_FN_CALL;
+
+       int ret, default_email=0;
+       GSList *added_emails=NULL, *email_repeat = email_list;
+       cts_email *email_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == email_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (email_data = (cts_email *)email_repeat->data))
+               {
+                       if (!email_data->id){
+                               if (!email_data->deleted)
+                                       added_emails = g_slist_append(added_emails, email_data);
+                               email_repeat = g_slist_next(email_repeat);
+                               continue;
+                       }
+                       if (email_data->deleted || NULL == email_data->email_addr) {
+                               ret = cts_delete_record_by_id(CTS_TABLE_DATA, email_data->id);
+                               retvm_if(ret, ret, "cts_delete_record_by_id() Failed(%d)", ret);
+                       }
+                       else
+                       {
+                               int cnt = 1;
+
+                               cts_stmt_bind_int(stmt, cnt++, email_data->type);
+                               cts_stmt_bind_text(stmt, cnt++, email_data->email_addr);
+                               cts_stmt_bind_int(stmt, CTS_UPDATE_ID_LOC, email_data->id);
+
+                               ret = cts_stmt_step(stmt);
+                               retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+
+                               if (email_data->is_default)
+                                       default_email = email_data->id;
+                               cts_stmt_reset(stmt);
+                       }
+               }
+               email_repeat = g_slist_next(email_repeat);
+       }while(email_repeat);
+
+       if (added_emails) {
+               contact_t temp;
+               cts_ct_base base;
+               temp.base = &base;
+               temp.base->id = contact_id;
+               temp.emails = added_emails;
+
+               ret = cts_insert_contact_data(CTS_DATA_FIELD_EMAIL, &temp);
+               if (temp.default_email) {
+                       email_repeat = added_emails;
+                       while (email_repeat) {
+                               if (NULL != (email_data = (cts_email *)email_repeat->data)) {
+                                       if (email_data->is_default) {
+                                               default_email = temp.default_email;
+                                               break;
+                                       }
+                               }
+                               email_repeat = email_repeat->next;
+                       }
+               }
+               g_slist_free(added_emails);
+               retvm_if(CTS_SUCCESS != ret, ret, "cts_insert_contact_data() Failed(%d)", ret);
+       }
+
+       return default_email;
+}
+
+static inline int cts_update_contact_grouprel(cts_ct_base *base_info,
+               GSList* group_list)
+{
+       CTS_FN_CALL;
+
+       int ret;
+       GSList *group_repeat = group_list;
+       cts_group *group_data;
+
+       retv_if(NULL == group_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               group_data = group_repeat->data;
+               group_repeat = group_repeat->next;
+
+               if (NULL == group_data)
+                       continue;
+
+               if (group_data->deleted) {
+                       ret = cts_group_unset_relation(group_data->id, base_info->id);
+                       retvm_if(ret, ret, "cts_group_unset_relation() Failed(%d)", ret);
+               }
+               else {
+                       if (group_data->vcard_group) {
+                               int found_id;
+                               found_id = contacts_svc_find_group(base_info->addrbook_id, group_data->vcard_group);
+                               if (0 < found_id)
+                                       group_data->id = found_id;
+                               else if (found_id == CTS_ERR_DB_RECORD_NOT_FOUND) {
+                                       CTSvalue *group;
+                                       group = contacts_svc_value_new(CTS_VALUE_GROUP);
+
+                                       contacts_svc_value_set_str(group, CTS_GROUP_VAL_NAME_STR, group_data->vcard_group);
+                                       found_id = contacts_svc_insert_group(base_info->addrbook_id, group);
+                                       if (found_id < CTS_SUCCESS)
+                                               ERR("contacts_svc_insert_group() Failed\n");
+                                       else
+                                               group_data->id = found_id;
+
+                                       contacts_svc_value_free(group);
+                               }
+                       }
+                       if (group_data->id) {
+                               ret = cts_group_set_relation(group_data->id, base_info->id,
+                                               base_info->addrbook_id);
+                               retvm_if(ret < CTS_SUCCESS, ret, "cts_group_set_relation() Failed(%d)", ret);
+                       }
+               }
+       }while(group_repeat);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_update_contact_data_event(
+               cts_stmt stmt, int contact_id, GSList* event_list)
+{
+       CTS_FN_CALL;
+
+       int ret;
+       GSList *added_event=NULL, *event_repeat = event_list;
+       cts_event *event_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == event_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (event_data = (cts_event *)event_repeat->data))
+               {
+                       if (!event_data->id){
+                               if (!event_data->deleted)
+                                       added_event = g_slist_append(added_event, event_data);
+                               event_repeat = g_slist_next(event_repeat);
+                               continue;
+                       }
+                       if (event_data->deleted) {
+                               ret = cts_delete_record_by_id(CTS_TABLE_DATA, event_data->id);
+                               retvm_if(ret, ret, "cts_delete_record_by_id() Failed(%d)", ret);
+                       }
+                       else
+                       {
+                               cts_stmt_bind_event(stmt, 1, event_data);
+                               cts_stmt_bind_int(stmt, CTS_UPDATE_ID_LOC, event_data->id);
+
+                               ret = cts_stmt_step(stmt);
+                               retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                               cts_stmt_reset(stmt);
+                       }
+               }
+               event_repeat = g_slist_next(event_repeat);
+       }while(event_repeat);
+
+       if (added_event) {
+               contact_t temp;
+               cts_ct_base base;
+               temp.base = &base;
+               temp.base->id = contact_id;
+               temp.events = added_event;
+
+               ret = cts_insert_contact_data(CTS_DATA_FIELD_EVENT, &temp);
+               g_slist_free(added_event);
+               retvm_if(CTS_SUCCESS != ret, ret,
+                               "cts_insert_contact_data() Failed(%d)", ret);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_update_contact_data_messenger(
+               cts_stmt stmt, int contact_id, GSList* messenger_list)
+{
+       CTS_FN_CALL;
+
+       int ret;
+       GSList *added_messenger=NULL, *messenger_repeat = messenger_list;
+       cts_messenger *messenger_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == messenger_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (messenger_data = (cts_messenger *)messenger_repeat->data))
+               {
+                       if (!messenger_data->id){
+                               if (!messenger_data->deleted)
+                                       added_messenger = g_slist_append(added_messenger, messenger_data);
+                               messenger_repeat = g_slist_next(messenger_repeat);
+                               continue;
+                       }
+                       if (messenger_data->deleted || NULL == messenger_data->im_id)
+                       {
+                               ret = cts_delete_record_by_id(CTS_TABLE_DATA, messenger_data->id);
+                               retvm_if(ret, ret, "cts_delete_record_by_id() Failed(%d)", ret);
+                       }
+                       else
+                       {
+                               cts_stmt_bind_messenger(stmt, 1, messenger_data);
+                               cts_stmt_bind_int(stmt, CTS_UPDATE_ID_LOC, messenger_data->id);
+
+                               ret = cts_stmt_step(stmt);
+                               retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                               cts_stmt_reset(stmt);
+                       }
+               }
+               messenger_repeat = g_slist_next(messenger_repeat);
+       }while(messenger_repeat);
+
+       if (added_messenger) {
+               contact_t temp;
+               cts_ct_base base;
+               temp.base = &base;
+               temp.base->id = contact_id;
+               temp.messengers = added_messenger;
+
+               ret = cts_insert_contact_data(CTS_DATA_FIELD_MESSENGER, &temp);
+               g_slist_free(added_messenger);
+               retvm_if(CTS_SUCCESS != ret, ret,
+                               "cts_insert_contact_data() Failed(%d)", ret);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_update_contact_data_postal(
+               cts_stmt stmt, int contact_id, GSList* postal_list)
+{
+       CTS_FN_CALL;
+
+       int ret;
+       GSList *added_postal=NULL, *postal_repeat = postal_list;
+       cts_postal *postal_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == postal_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (postal_data = (cts_postal *)postal_repeat->data))
+               {
+                       if (!postal_data->id){
+                               if (!postal_data->deleted)
+                                       added_postal = g_slist_append(added_postal, postal_data);
+                               postal_repeat = g_slist_next(postal_repeat);
+                               continue;
+                       }
+                       if (postal_data->deleted || !(postal_data->country || postal_data->pobox
+                                               || postal_data->postalcode || postal_data->region
+                                               || postal_data->locality || postal_data->street || postal_data->extended))
+                       {
+                               ret = cts_delete_record_by_id(CTS_TABLE_DATA, postal_data->id);
+                               retvm_if(ret, ret, "cts_delete_record_by_id() Failed(%d)", ret);
+                       }
+                       else
+                       {
+                               cts_stmt_bind_postal(stmt, 1, postal_data);
+                               cts_stmt_bind_int(stmt, CTS_UPDATE_ID_LOC, postal_data->id);
+
+                               ret = cts_stmt_step(stmt);
+                               retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                               cts_stmt_reset(stmt);
+                       }
+               }
+               postal_repeat = g_slist_next(postal_repeat);
+       }while(postal_repeat);
+
+       if (added_postal) {
+               contact_t temp;
+               cts_ct_base base;
+               temp.base = &base;
+               temp.base->id = contact_id;
+               temp.postal_addrs = added_postal;
+
+               ret = cts_insert_contact_data(CTS_DATA_FIELD_POSTAL, &temp);
+               g_slist_free(added_postal);
+               retvm_if(CTS_SUCCESS != ret, ret,
+                               "cts_insert_contact_data() Failed(%d)", ret);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_update_contact_data_web(
+               cts_stmt stmt, int contact_id, GSList* web_list)
+{
+       CTS_FN_CALL;
+
+       int ret;
+       GSList *added_web=NULL, *web_repeat = web_list;
+       cts_web *web_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == web_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (web_data = (cts_web *)web_repeat->data))
+               {
+                       if (!web_data->id){
+                               if (!web_data->deleted)
+                                       added_web = g_slist_append(added_web, web_data);
+                               web_repeat = g_slist_next(web_repeat);
+                               continue;
+                       }
+                       if (web_data->deleted || NULL == web_data->url)
+                       {
+                               ret = cts_delete_record_by_id(CTS_TABLE_DATA, web_data->id);
+                               retvm_if(ret, ret, "cts_delete_record_by_id() Failed(%d)", ret);
+                       }
+                       else
+                       {
+                               cts_stmt_bind_web(stmt, 1, web_data);
+                               cts_stmt_bind_int(stmt, CTS_UPDATE_ID_LOC, web_data->id);
+
+                               ret = cts_stmt_step(stmt);
+                               retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                               cts_stmt_reset(stmt);
+                       }
+               }
+               web_repeat = g_slist_next(web_repeat);
+       }while(web_repeat);
+
+       if (added_web) {
+               contact_t temp;
+               cts_ct_base base;
+               temp.base = &base;
+               temp.base->id = contact_id;
+               temp.web_addrs = added_web;
+
+               ret = cts_insert_contact_data(CTS_DATA_FIELD_WEB, &temp);
+               g_slist_free(added_web);
+               retvm_if(CTS_SUCCESS != ret, ret,
+                               "cts_insert_contact_data() Failed(%d)", ret);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_update_contact_data_nick(
+               cts_stmt stmt, int contact_id, GSList* nick_list)
+{
+       CTS_FN_CALL;
+
+       int ret;
+       GSList *added_nick=NULL, *nick_repeat = nick_list;
+       cts_nickname *nick_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == nick_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (nick_data = (cts_nickname *)nick_repeat->data))
+               {
+                       if (!nick_data->id){
+                               if (!nick_data->deleted)
+                                       added_nick = g_slist_append(added_nick, nick_data);
+                               nick_repeat = g_slist_next(nick_repeat);
+                               continue;
+                       }
+                       if (nick_data->deleted || NULL == nick_data->nick)
+                       {
+                               ret = cts_delete_record_by_id(CTS_TABLE_DATA, nick_data->id);
+                               retvm_if(ret, ret, "cts_delete_record_by_id() Failed(%d)", ret);
+                       }
+                       else
+                       {
+                               cts_stmt_bind_text(stmt, 2, nick_data->nick);
+                               cts_stmt_bind_int(stmt, CTS_UPDATE_ID_LOC, nick_data->id);
+
+                               ret = cts_stmt_step(stmt);
+                               retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                               cts_stmt_reset(stmt);
+                       }
+               }
+               nick_repeat = g_slist_next(nick_repeat);
+       }while(nick_repeat);
+
+       if (added_nick) {
+               contact_t temp;
+               cts_ct_base base;
+               temp.base = &base;
+               temp.base->id = contact_id;
+               temp.nicknames = added_nick;
+
+               ret = cts_insert_contact_data(CTS_DATA_FIELD_NICKNAME, &temp);
+               g_slist_free(added_nick);
+               retvm_if(CTS_SUCCESS != ret, ret,
+                               "cts_insert_contact_data() Failed(%d)", ret);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_update_contact_data_extend(
+               cts_stmt stmt, int contact_id, GSList* extend_list)
+{
+       CTS_FN_CALL;
+
+       int ret;
+       GSList *added_extend=NULL, *extend_repeat = extend_list;
+       cts_extend *extend_data;
+
+       retv_if(NULL == stmt, CTS_ERR_ARG_NULL);
+       retv_if(NULL == extend_list, CTS_ERR_ARG_NULL);
+
+       do
+       {
+               if (NULL != (extend_data = (cts_extend *)extend_repeat->data))
+               {
+                       if (!extend_data->id){
+                               if (!extend_data->deleted)
+                                       added_extend = g_slist_append(added_extend, extend_data);
+                               extend_repeat = g_slist_next(extend_repeat);
+                               continue;
+                       }
+                       if (extend_data->deleted)
+                       {
+                               ret = cts_delete_record_by_id(CTS_TABLE_DATA, extend_data->id);
+                               retvm_if(ret, ret, "cts_delete_record_by_id() Failed(%d)", ret);
+                       }
+                       else
+                       {
+                               cts_stmt_bind_extend(stmt, 1, extend_data);
+                               cts_stmt_bind_int(stmt, CTS_UPDATE_ID_LOC, extend_data->id);
+
+                               ret = cts_stmt_step(stmt);
+                               retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+                               cts_stmt_reset(stmt);
+                       }
+               }
+               extend_repeat = g_slist_next(extend_repeat);
+       }while(extend_repeat);
+
+       if (added_extend) {
+               contact_t temp;
+               cts_ct_base base;
+               temp.base = &base;
+               temp.base->id = contact_id;
+               temp.extended_values = added_extend;
+
+               ret = cts_insert_contact_data(CTS_DATA_FIELD_EXTEND_ALL, &temp);
+               g_slist_free(added_extend);
+               retvm_if(CTS_SUCCESS != ret, ret,
+                               "cts_insert_contact_data() Failed(%d)", ret);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_update_contact_data_name(cts_stmt stmt,
+               cts_name *name)
+{
+       int ret, cnt=1;
+       cts_name normalize_name={0};
+       char *tmp_display, *tmp_first, *tmp_last;
+       char display[CTS_SQL_MAX_LEN]={0};
+       char lookup[CTS_SQL_MAX_LEN]={0};
+       char reverse_lookup[CTS_SQL_MAX_LEN]={0};
+
+       retvm_if(!name->id, CTS_ERR_ARG_INVALID, "name of contact has no ID.");
+       cts_stmt_bind_int(stmt, CTS_UPDATE_ID_LOC, name->id);
+
+       //Update name search info
+       char normal_name[CTS_NN_MAX][CTS_SQL_MAX_LEN]={{0},{0},{0}};
+
+       tmp_display = name->display;
+       tmp_first = name->first;
+       tmp_last = name->last;
+
+       if (name->display) {
+               ret = cts_normalize_name(name, normal_name, true);
+               retvm_if(ret < CTS_SUCCESS, ret, "cts_normalize_name() Failed(%d)", ret);
+               if (normal_name[CTS_NN_FIRST][0])
+                       normalize_name.display = normal_name[CTS_NN_FIRST];
+               else
+                       name->display = NULL;
+       }
+
+       if (NULL == name->display) {
+               ret = cts_normalize_name(name, normal_name, false);
+               retvm_if(ret < CTS_SUCCESS, ret, "cts_normalize_name() Failed(%d)", ret);
+
+               switch (ret)
+               {
+               case CTS_LANG_KOREAN:
+                       snprintf(display, sizeof(display), "%s%s",
+                                       SAFE_STR(name->last), SAFE_STR(name->first));
+
+                       strncat(normal_name[CTS_NN_LAST], normal_name[CTS_NN_FIRST],
+                                       sizeof(normal_name[CTS_NN_LAST]));
+
+                       name->display = display;
+                       normalize_name.display = normal_name[CTS_NN_LAST];
+                       break;
+               case CTS_LANG_ENGLISH:
+               default:
+                       if (normal_name[CTS_NN_FIRST][0])
+                               normalize_name.first = normal_name[CTS_NN_FIRST];
+                       else
+                               name->first = NULL;
+
+                       if (normal_name[CTS_NN_LAST][0])
+                               normalize_name.last = normal_name[CTS_NN_LAST];
+                       else
+                               name->last = NULL;
+
+                       break;
+               }
+       }
+
+       if (cts_get_default_language() == ret)
+               cts_stmt_bind_int(stmt, cnt, CTS_LANG_DEFAULT);
+       else
+               cts_stmt_bind_int(stmt, cnt, ret);
+       cnt = cts_stmt_bind_name(stmt, cnt, name);
+
+       name->display = tmp_display;
+       name->first = tmp_first;
+       name->last = tmp_last;
+
+       ret = cts_make_name_lookup(CTS_ORDER_NAME_FIRSTLAST, &normalize_name,
+                                                                               lookup, sizeof(lookup));
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_make_name_lookup() Failed(%d)", ret);
+
+       ret = cts_make_name_lookup(CTS_ORDER_NAME_LASTFIRST, &normalize_name,
+                                                                               reverse_lookup, sizeof(reverse_lookup));
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_make_name_lookup() Failed(%d)", ret);
+
+       CTS_DBG("lookup=%s(%d), reverse_lookup=%s(%d)",
+                       lookup, strlen(lookup), reverse_lookup, strlen(reverse_lookup));
+
+       cts_stmt_bind_text(stmt, cnt++, lookup);
+       cts_stmt_bind_text(stmt, cnt++, reverse_lookup);
+       cts_stmt_bind_text(stmt, cnt, normal_name[CTS_NN_SORTKEY]);
+
+       ret = cts_stmt_step(stmt);
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_stmt_step() Failed(%d)", ret);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_update_contact_data(contact_t *contact)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       // Use stmt query for DATA table
+       snprintf(query, sizeof(query), "UPDATE %s SET data1=?, data2=?, data3=?, data4=?,"
+                       "data5=?, data6=?, data7=?, data8=?, data9=?, data10=? WHERE id=?",
+                       CTS_TABLE_DATA);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       //Update the name
+       if (contact->name && contact->name->is_changed)
+       {
+               ret = cts_update_contact_data_name(stmt, contact->name);
+               if (CTS_SUCCESS != ret) {
+                       ERR("cts_update_contact_data_name() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+               cts_stmt_reset(stmt);
+       }
+
+       //Update the company
+       if (contact->company)
+       {
+               cts_company *com = contact->company;
+               if (!com->id) {
+                       ret = cts_insert_contact_data(CTS_DATA_FIELD_COMPANY, contact);
+                       retvm_if(CTS_SUCCESS != ret, ret,
+                                       "cts_insert_contact_data(CTS_DATA_FIELD_COMPANY) Failed(%d)", ret);
+               }
+               else {
+                       if (com->name || com->department || com->jot_title || com->role || com->assistant_name) {
+                               cts_stmt_bind_company(stmt, 1, com);
+                               cts_stmt_bind_int(stmt, CTS_UPDATE_ID_LOC, com->id);
+
+                               ret = cts_stmt_step(stmt);
+                               if (CTS_SUCCESS != ret)
+                               {
+                                       ERR("cts_stmt_step() Failed(%d)", ret);
+                                       cts_stmt_finalize(stmt);
+                                       return ret;
+                               }
+                               cts_stmt_reset(stmt);
+                       }
+                       else {
+                               ret = cts_delete_record_by_id(CTS_TABLE_DATA, com->id);
+                               retvm_if(ret, ret, "cts_delete_record_by_id() Failed(%d)", ret);
+                       }
+               }
+       }
+
+       //Update the events
+       if (contact->events)
+       {
+               ret = cts_update_contact_data_event(stmt, contact->base->id, contact->events);
+
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_update_contact_data_event() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+       }
+
+       //Update the messengers
+       if (contact->messengers)
+       {
+               ret = cts_update_contact_data_messenger(stmt, contact->base->id,
+                               contact->messengers);
+
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_update_contact_data_messenger() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+       }
+
+       //Update the postals
+       if (contact->postal_addrs)
+       {
+               ret = cts_update_contact_data_postal(stmt, contact->base->id,
+                               contact->postal_addrs);
+
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_update_contact_data_postal() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+       }
+
+       //Update the Web addrs
+       if (contact->web_addrs)
+       {
+               ret = cts_update_contact_data_web(stmt, contact->base->id, contact->web_addrs);
+
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_update_contact_data_web() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+       }
+
+       //Update the Nick Names
+       if (contact->nicknames)
+       {
+               ret = cts_update_contact_data_nick(stmt, contact->base->id, contact->nicknames);
+
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_update_contact_data_nick() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+       }
+
+       //Update the Numbers
+       if (contact->numbers)
+       {
+               ret = cts_update_contact_data_number(stmt, contact->base->id, contact->numbers);
+
+               if (ret < CTS_SUCCESS)
+               {
+                       ERR("cts_update_contact_data_number() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+               contact->default_num = ret;
+       }
+
+       //Update the Emails
+       if (contact->emails)
+       {
+               ret = cts_update_contact_data_email(stmt, contact->base->id, contact->emails);
+
+               if (ret < CTS_SUCCESS)
+               {
+                       ERR("cts_update_contact_data_email() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+               contact->default_email = ret;
+       }
+
+       //Update the extended values
+       if (contact->extended_values)
+       {
+               ret = cts_update_contact_data_extend(stmt, contact->base->id,
+                               contact->extended_values);
+
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_update_contact_data_extend() Failed(%d)", ret);
+                       cts_stmt_finalize(stmt);
+                       return ret;
+               }
+       }
+
+       cts_stmt_finalize(stmt);
+
+       return CTS_SUCCESS;
+}
+
+
+static inline void cts_update_contact_handle_no_name(contact_t *contact)
+{
+       if (NULL == contact->name) {
+               contact->name = calloc(1, sizeof(cts_name));
+               contact->name->embedded = true;
+       } else if (contact->name->first || contact->name->last) {
+               return;
+       }
+
+       if (contact->name->display) {
+               free(contact->name->display);
+               contact->name->display = NULL;
+       }
+       contact->name->is_changed = true;
+
+       if (contact->company && contact->company->name) {
+               contact->name->display = strdup(contact->company->name);
+       } else {
+               char *temp;
+
+               temp = cts_contact_get_valid_first_number_or_email(contact->numbers, contact->emails);
+               contact->name->display = SAFE_STRDUP(temp);
+       }
+}
+
+
+static inline int cts_update_contact(contact_t *contact)
+{
+       int i, ret, len;
+       char query[CTS_SQL_MAX_LEN] = {0};
+       char *img_path;
+
+       snprintf(query, sizeof(query),
+                       "SELECT count(contact_id) FROM %s WHERE contact_id = %d",
+                       CTS_TABLE_CONTACTS, contact->base->id);
+       ret = cts_query_get_first_int_result(query);
+       retvm_if(1 != ret, CTS_ERR_DB_RECORD_NOT_FOUND,
+                       "The index(%d) is Invalid. %d Record(s) is(are) found", contact->base->id, ret);
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       cts_update_contact_handle_no_name(contact);
+       cts_contact_remove_dup_data(contact);
+
+       //update data
+       ret = cts_update_contact_data(contact);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_update_contact_data() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       //update group relation Info
+       if (contact->grouprelations)
+       {
+               ret = cts_update_contact_grouprel(contact->base, contact->grouprelations);
+               if (ret < CTS_SUCCESS)
+               {
+                       ERR("cts_update_contact_grouprel() Failed(%d)", ret);
+                       contacts_svc_end_trans(false);
+                       return ret;
+               }
+       }
+
+       // default setting
+       if (!contact->default_num || !contact->default_email) {
+               ret = cts_set_first_id_for_default(contact);
+               if (CTS_SUCCESS != ret) {
+                       ERR("cts_set_first_id_for_default() Failed(%d)", ret);
+                       contacts_svc_end_trans(false);
+                       return ret;
+               }
+       }
+       len = snprintf(query, sizeof(query),
+                       "UPDATE %s SET changed_ver=%d, changed_time=%d, "
+                       "default_num=%d, default_email=%d",
+                       CTS_TABLE_CONTACTS, cts_get_next_ver(), (int)time(NULL),
+                       contact->default_num, contact->default_email);
+
+       if (contact->base->uid_changed)
+               len += snprintf(query+len, sizeof(query)-len, ", uid=?");
+
+       if (contact->base->ringtone_changed)
+               len += snprintf(query+len, sizeof(query)-len, ", ringtone=?");
+
+       if (contact->base->note_changed)
+               len += snprintf(query+len, sizeof(query)-len, ", note=?");
+
+       if (contact->base->img_changed ||
+                       (NULL == contact->base->img_path && contact->base->vcard_img_path))
+               len += snprintf(query+len, sizeof(query)-len, ", image0=?");
+
+       if (contact->base->full_img_changed)
+               len += snprintf(query+len, sizeof(query)-len, ", image1=?");
+
+       snprintf(query+len, sizeof(query)-len,
+                       " WHERE contact_id=%d", contact->base->id);
+
+       cts_stmt stmt = cts_query_prepare(query);
+       if (NULL == stmt) {
+               ERR("cts_query_prepare() Failed");
+               contacts_svc_end_trans(false);
+               return CTS_ERR_DB_FAILED;
+       }
+
+       i=1;
+       if (contact->base->uid_changed) {
+               if (contact->base->uid)
+                       cts_stmt_bind_text(stmt, i, contact->base->uid);
+               i++;
+       }
+       if (contact->base->ringtone_changed) {
+               if (contact->base->ringtone_path)
+                       cts_stmt_bind_text(stmt, i, contact->base->ringtone_path);
+               i++;
+       }
+       if (contact->base->note_changed) {
+               if (contact->base->note)
+                       cts_stmt_bind_text(stmt, i, contact->base->note);
+               i++;
+       }
+
+       if (contact->base->img_changed ||
+                       (NULL == contact->base->img_path && contact->base->vcard_img_path)) {
+               if (contact->base->img_path) {
+                       ret = cts_update_image_file(CTS_IMG_NORMAL, contact->base->id, contact->base->img_path, &img_path);
+                       if (CTS_SUCCESS != ret) {
+                               ERR("cts_update_image_file() Failed(%d)", ret);
+                               cts_stmt_finalize(stmt);
+                               contacts_svc_end_trans(false);
+                               return ret;
+                       }
+                       if (img_path)
+                               cts_stmt_bind_text(stmt, i, img_path);
+                       i++;
+               } else {
+                       if (contact->base->vcard_img_path) {
+                               ret = cts_update_image_file(CTS_IMG_NORMAL, contact->base->id, contact->base->vcard_img_path, &img_path);
+                               if (CTS_SUCCESS == ret && img_path)
+                                       cts_stmt_bind_text(stmt, i, img_path);
+                               i++;
+                       } else {
+                               ret = cts_delete_image_file(CTS_IMG_NORMAL, contact->base->id);
+                               if (CTS_SUCCESS != ret) {
+                                       ERR("cts_delete_image_file() Failed(%d)", ret);
+                                       cts_stmt_finalize(stmt);
+                                       contacts_svc_end_trans(false);
+                                       return ret;
+                               }
+                       }
+               }
+       }
+
+       if (contact->base->full_img_changed) {
+               ret = cts_update_image_file(CTS_IMG_FULL, contact->base->id, contact->base->full_img_path, &img_path);
+               if (CTS_SUCCESS == ret && img_path)
+                       cts_stmt_bind_text(stmt, i, img_path);
+               i++;
+       }
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       cts_stmt_finalize(stmt);
+
+       cts_set_contact_noti();
+
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_update_contact(CTSstruct* contact)
+{
+       CTS_FN_CALL;
+       int ret;
+
+       retv_if(NULL == contact, CTS_ERR_ARG_NULL);
+       retvm_if(CTS_STRUCT_CONTACT != contact->s_type, CTS_ERR_ARG_INVALID,
+                       "The contact(%d) must be type of CTS_STRUCT_CONTACT.", contact->s_type);
+
+       CTS_START_TIME_CHECK;
+
+       ret = cts_update_contact((contact_t *)contact);
+
+       CTS_END_TIME_CHECK();
+       return ret;
+}
+
+static inline int cts_put_base_val(int op_code, int contact_id,
+               cts_ct_base *value)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MIN_LEN] = {0};
+
+       retvm_if(CTS_VALUE_CONTACT_BASE_INFO != value->v_type, CTS_ERR_ARG_INVALID,
+                       "value has unknown type");
+       switch (op_code) {
+       case CTS_PUT_VAL_REPLACE_RINGTONE:
+               snprintf(query, sizeof(query),
+                               "UPDATE %s SET changed_ver=%d, changed_time=%d, "
+                               "ringtone=? WHERE contact_id=%d",
+                               CTS_TABLE_CONTACTS, cts_get_next_ver(), (int)time(NULL),
+                               contact_id);
+
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+               if (value->ringtone_path)
+                       cts_stmt_bind_text(stmt, 1, value->ringtone_path);
+               break;
+       case CTS_PUT_VAL_REPLACE_NOTE:
+               snprintf(query, sizeof(query),
+                               "UPDATE %s SET changed_ver=%d, changed_time=%d, "
+                               "note=? WHERE contact_id=%d",
+                               CTS_TABLE_CONTACTS, cts_get_next_ver(), (int)time(NULL),
+                               contact_id);
+
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+               if (value->note)
+                       cts_stmt_bind_text(stmt, 1, value->note);
+               break;
+       default:
+               ERR("Invalid parameter : The op_code(%d) is not supported", op_code);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return ret;
+       }
+       cts_stmt_finalize(stmt);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_put_number_val(int contact_id,
+               cts_number *number)
+{
+       int ret, default_id;
+       cts_stmt stmt = NULL;
+       char clean_num[CTS_NUMBER_MAX_LEN], query[CTS_SQL_MAX_LEN] = {0};
+       const char *normal_num;
+
+       retv_if(NULL == number->number, CTS_ERR_ARG_NULL);
+       retvm_if(CTS_VALUE_NUMBER != number->v_type, CTS_ERR_ARG_INVALID,
+                       "value has unknown type");
+
+       ret = cts_clean_number(number->number, clean_num, sizeof(clean_num));
+       retvm_if(ret <= 0, CTS_ERR_ARG_INVALID, "Number(%s) is invalid", number->number);
+
+       snprintf(query, sizeof(query),
+                       "INSERT INTO %s(contact_id, datatype, data1, data2, data3) VALUES(%d, %d, %d, ?, ?)",
+                       CTS_TABLE_DATA, contact_id, CTS_DATA_NUMBER, number->type);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       cts_stmt_bind_text(stmt, 1, clean_num);
+
+       normal_num = cts_normalize_number(clean_num);
+       cts_stmt_bind_text(stmt, 2, normal_num);
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return ret;
+       }
+       cts_stmt_finalize(stmt);
+
+       if (number->is_default) {
+               default_id = cts_db_get_last_insert_id();
+               snprintf(query, sizeof(query),
+                               "UPDATE %s SET changed_ver=%d, changed_time=%d, default_num=%d "
+                               "WHERE contact_id=%d",
+                               CTS_TABLE_CONTACTS, cts_get_next_ver(), (int)time(NULL),
+                               default_id, contact_id);
+       } else {
+               snprintf(query, sizeof(query),
+                               "UPDATE %s SET changed_ver=%d, changed_time=%d WHERE contact_id=%d",
+                               CTS_TABLE_CONTACTS, cts_get_next_ver(), (int)time(NULL),
+                               contact_id);
+       }
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               return ret;
+       }
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_put_email_val(int contact_id,
+               cts_email *email)
+{
+       int ret, default_id;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       retv_if(NULL == email->email_addr, CTS_ERR_ARG_NULL);
+       retvm_if(CTS_VALUE_EMAIL != email->v_type, CTS_ERR_ARG_INVALID,
+                       "value has unknown type");
+
+       snprintf(query, sizeof(query),
+                       "INSERT INTO %s(contact_id, datatype, data1, data2) VALUES(%d, %d, %d, ?)",
+                       CTS_TABLE_DATA, contact_id, CTS_DATA_EMAIL, email->type);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       if (email->email_addr)
+               cts_stmt_bind_text(stmt, 1, email->email_addr);
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return ret;
+       }
+       cts_stmt_finalize(stmt);
+
+       if (email->is_default) {
+               default_id = cts_db_get_last_insert_id();
+               snprintf(query, sizeof(query),
+                               "UPDATE %s SET changed_ver=%d, changed_time=%d, default_email=%d "
+                               "WHERE contact_id=%d",
+                               CTS_TABLE_CONTACTS, cts_get_next_ver(), (int)time(NULL),
+                               default_id, contact_id);
+       } else {
+               snprintf(query, sizeof(query),
+                               "UPDATE %s SET changed_ver=%d, changed_time=%d WHERE contact_id=%d",
+                               CTS_TABLE_CONTACTS, cts_get_next_ver(), (int)time(NULL),
+                               contact_id);
+       }
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               return ret;
+       }
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_put_contact_value(cts_put_contact_val_op op_code,
+               int contact_id, CTSvalue* value)
+{
+       CTS_FN_CALL;
+
+       int ret;
+
+       retv_if(NULL == value, CTS_ERR_ARG_NULL);
+       CTS_START_TIME_CHECK;
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       switch (op_code)
+       {
+       case CTS_PUT_VAL_REPLACE_RINGTONE:
+       case CTS_PUT_VAL_REPLACE_NOTE:
+               ret = cts_put_base_val(op_code, contact_id, (cts_ct_base *)value);
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_update_contact_val_ringtone() Failed(%d)", ret);
+                       contacts_svc_end_trans(false);
+                       return ret;
+               }
+               break;
+       case CTS_PUT_VAL_ADD_NUMBER:
+               ret = cts_put_number_val(contact_id, (cts_number *)value);
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_put_number_val() Failed(%d)", ret);
+                       contacts_svc_end_trans(false);
+                       return ret;
+               }
+               break;
+       case CTS_PUT_VAL_ADD_EMAIL:
+               ret = cts_put_email_val(contact_id, (cts_email *)value);
+               if (CTS_SUCCESS != ret)
+               {
+                       ERR("cts_put_email_val() Failed(%d)", ret);
+                       contacts_svc_end_trans(false);
+                       return ret;
+               }
+               break;
+       default:
+               ERR("Invalid parameter : The op_code(%d) is not supported", op_code);
+               contacts_svc_end_trans(false);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       cts_set_contact_noti();
+
+       ret = contacts_svc_end_trans(true);
+       CTS_END_TIME_CHECK();
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+#define CTS_MAIN_CTS_GET_RINGTON (1<<1)
+#define CTS_MAIN_CTS_GET_NOTE (1<<2)
+#define CTS_MAIN_CTS_GET_DEFAULT_NUM (1<<3)
+#define CTS_MAIN_CTS_GET_DEFAULT_EMAIL (1<<4)
+#define CTS_MAIN_CTS_GET_FAVOR (1<<5)
+#define CTS_MAIN_CTS_GET_IMG (1<<6)
+#define CTS_MAIN_CTS_GET_ALL (1<<1|1<<2|1<<3|1<<4|1<<5|1<<6)
+
+static int cts_get_main_contacts_info(int op_code, int index, contact_t *contact)
+{
+       int ret, len;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+       char *temp;
+
+       len = snprintf(query, sizeof(query), "SELECT ");
+
+       len += snprintf(query+len, sizeof(query)-len,
+                       "contact_id, addrbook_id, changed_time");
+
+       if (op_code & CTS_MAIN_CTS_GET_RINGTON)
+               len += snprintf(query+len, sizeof(query)-len, ", ringtone");
+       if (op_code & CTS_MAIN_CTS_GET_NOTE)
+               len += snprintf(query+len, sizeof(query)-len, ", note");
+       if (op_code & CTS_MAIN_CTS_GET_DEFAULT_NUM)
+               len += snprintf(query+len, sizeof(query)-len, ", default_num");
+       if (op_code & CTS_MAIN_CTS_GET_DEFAULT_EMAIL)
+               len += snprintf(query+len, sizeof(query)-len, ", default_email");
+       if (op_code & CTS_MAIN_CTS_GET_FAVOR)
+               len += snprintf(query+len, sizeof(query)-len, ", is_favorite");
+       if (op_code & CTS_MAIN_CTS_GET_IMG) {
+               len += snprintf(query+len, sizeof(query)-len, ", image0");
+               len += snprintf(query+len, sizeof(query)-len, ", image1");
+       }
+
+       snprintf(query+len, sizeof(query)-len,
+                       " FROM %s WHERE contact_id = %d", CTS_TABLE_CONTACTS, index);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_DB_RECORD_NOT_FOUND;
+       }
+       int count=0;
+
+       contact->base = (cts_ct_base *)contacts_svc_value_new(CTS_VALUE_CONTACT_BASE_INFO);
+       if (NULL == contact->base) {
+               cts_stmt_finalize(stmt);
+               ERR("contacts_svc_value_new(CTS_VALUE_CONTACT_BASE_INFO) Failed");
+               return CTS_ERR_OUT_OF_MEMORY;
+       }
+
+       contact->base->id = cts_stmt_get_int(stmt, count++);
+       contact->base->addrbook_id = cts_stmt_get_int(stmt, count++);
+       contact->base->changed_time = cts_stmt_get_int(stmt, count++);
+
+       if (op_code & CTS_MAIN_CTS_GET_RINGTON)
+       {
+               contact->base->embedded = true;
+               temp = cts_stmt_get_text(stmt, count++);
+               if (temp && CTS_SUCCESS == cts_exist_file(temp))
+                       contact->base->ringtone_path = strdup(temp);
+               else
+                       contact->base->ringtone_path = NULL;
+       }
+       if (op_code & CTS_MAIN_CTS_GET_NOTE)
+       {
+               contact->base->embedded = true;
+               temp = cts_stmt_get_text(stmt, count++);
+               contact->base->note = SAFE_STRDUP(temp);
+       }
+       if (op_code & CTS_MAIN_CTS_GET_DEFAULT_NUM)
+               contact->default_num = cts_stmt_get_int(stmt, count++);
+       if (op_code & CTS_MAIN_CTS_GET_DEFAULT_EMAIL)
+               contact->default_email = cts_stmt_get_int(stmt, count++);
+       if (op_code & CTS_MAIN_CTS_GET_FAVOR)
+               contact->base->is_favorite = cts_stmt_get_int(stmt, count++);
+
+       if (op_code & CTS_MAIN_CTS_GET_IMG) {
+               contact->base->embedded = true;
+               temp = cts_stmt_get_text(stmt, count++);
+               contact->base->img_path = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, count++);
+               contact->base->full_img_path = SAFE_STRDUP(temp);
+       }
+
+       cts_stmt_finalize(stmt);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_get_data_info_number(cts_stmt stmt, contact_t *contact)
+{
+       cts_number *result;
+
+       result = (cts_number *)contacts_svc_value_new(CTS_VALUE_NUMBER);
+       if (result) {
+               int cnt = 1;
+               result->embedded = true;
+               cnt = cts_stmt_get_number(stmt, result, cnt);
+
+               if (result->id == contact->default_num)
+                       result->is_default = true;
+
+               result->is_favorite = cts_stmt_get_int(stmt, cnt);
+               contact->numbers = g_slist_append(contact->numbers, result);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_get_data_info_email(cts_stmt stmt, contact_t *contact)
+{
+       cts_email *result;
+
+       result = (cts_email *)contacts_svc_value_new(CTS_VALUE_EMAIL);
+       if (result) {
+               result->embedded = true;
+               cts_stmt_get_email(stmt, result, 1);
+
+               if (result->id == contact->default_email)
+                       result->is_default = true;
+
+               contact->emails = g_slist_append(contact->emails, result);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline cts_name* cts_get_data_info_name(cts_stmt stmt)
+{
+       cts_name *result;
+
+       result = (cts_name *)contacts_svc_value_new(CTS_VALUE_NAME);
+       if (result) {
+               result->embedded = true;
+               cts_stmt_get_name(stmt, result, 1);
+       }
+       return result;
+}
+
+static inline int cts_get_data_info_event(cts_stmt stmt, contact_t *contact)
+{
+       int cnt=1;
+       cts_event *result;
+
+       result = (cts_event *)contacts_svc_value_new(CTS_VALUE_EVENT);
+       if (result) {
+               result->embedded = true;
+               result->id = cts_stmt_get_int(stmt, cnt++);
+               result->type = cts_stmt_get_int(stmt, cnt++);
+               result->date = cts_stmt_get_int(stmt, cnt++);
+
+               contact->events = g_slist_append(contact->events, result);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_get_data_info_messenger(cts_stmt stmt, contact_t *contact)
+{
+       int cnt=1;
+       cts_messenger *result;
+
+       result = (cts_messenger *)contacts_svc_value_new(CTS_VALUE_MESSENGER);
+       if (result) {
+               char *temp;
+               result->embedded = true;
+               result->id = cts_stmt_get_int(stmt, cnt++);
+               result->type = cts_stmt_get_int(stmt, cnt++);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->im_id = SAFE_STRDUP(temp);
+
+               contact->messengers = g_slist_append(contact->messengers, result);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_get_data_info_postal(cts_stmt stmt, contact_t *contact)
+{
+       int cnt=1;
+       cts_postal *result;
+
+       result = (cts_postal *)contacts_svc_value_new(CTS_VALUE_POSTAL);
+       if (result) {
+               char *temp;
+               result->embedded = true;
+               result->id = cts_stmt_get_int(stmt, cnt++);
+               result->type = cts_stmt_get_int(stmt, cnt++);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->pobox= SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->postalcode = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->region= SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->locality = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->street = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->extended = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->country = SAFE_STRDUP(temp);
+
+               contact->postal_addrs = g_slist_append(contact->postal_addrs, result);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_get_data_info_web(cts_stmt stmt, contact_t *contact)
+{
+       int cnt=1;
+       cts_web *result;
+
+       result = (cts_web *)contacts_svc_value_new(CTS_VALUE_WEB);
+       if (result) {
+               char *temp;
+               result->embedded = true;
+               result->id = cts_stmt_get_int(stmt, cnt++);
+               result->type = cts_stmt_get_int(stmt, cnt++);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->url = SAFE_STRDUP(temp);
+
+               contact->web_addrs = g_slist_append(contact->web_addrs, result);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_get_data_info_nick(cts_stmt stmt, contact_t *contact)
+{
+       int cnt=1;
+       cts_nickname *result;
+
+       result = (cts_nickname *)contacts_svc_value_new(CTS_VALUE_NICKNAME);
+       if (result) {
+               char *temp;
+               result->embedded = true;
+               result->id = cts_stmt_get_int(stmt, cnt++);
+               temp = cts_stmt_get_text(stmt, cnt+1);
+               result->nick = SAFE_STRDUP(temp);
+
+               contact->nicknames = g_slist_append(contact->nicknames, result);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline cts_company* cts_get_data_info_company(cts_stmt stmt)
+{
+       int cnt=1;
+       cts_company *result;
+
+       result = (cts_company *)contacts_svc_value_new(CTS_VALUE_COMPANY);
+       retvm_if(NULL == result, NULL, "contacts_svc_value_new() Failed");
+
+       char *temp;
+       result->embedded = true;
+       result->id = cts_stmt_get_int(stmt, cnt++);
+       cnt++;
+       temp = cts_stmt_get_text(stmt, cnt++);
+       result->name = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, cnt++);
+       result->department = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, cnt++);
+       result->jot_title = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, cnt++);
+       result->role = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, cnt++);
+       result->assistant_name = SAFE_STRDUP(temp);
+
+       if (result->name || result->department || result->jot_title || result->role ||  result->assistant_name)
+               return result;
+       else {
+               contacts_svc_value_free((CTSvalue *)result);
+               return NULL;
+       }
+}
+
+static cts_extend* cts_make_extend_data(cts_stmt stmt, int type, int cnt)
+{
+       cts_extend *result;
+       result = (cts_extend *)contacts_svc_value_new(CTS_VALUE_EXTEND);
+       if (result)
+       {
+               char *temp;
+               result->type = type;
+               result->id = cts_stmt_get_int(stmt, cnt++);
+               result->data1 = cts_stmt_get_int(stmt, cnt++);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->data2= SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->data3 = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->data4= SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->data5 = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->data6 = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->data7 = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->data8 = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->data9 = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->data10 = SAFE_STRDUP(temp);
+       }
+       return result;
+}
+
+static inline int cts_get_data_info_extend(cts_stmt stmt, int type,
+               contact_t *contact)
+{
+       cts_extend *result;
+
+       result = cts_make_extend_data(stmt, type, 1);
+       if (result) {
+               result->embedded = true;
+               contact->extended_values = g_slist_append(contact->extended_values, result);
+       }
+       else
+               return CTS_ERR_OUT_OF_MEMORY;
+
+       return CTS_SUCCESS;
+}
+
+enum{
+       CTS_GET_DATA_BY_CONTACT_ID,
+       CTS_GET_DATA_BY_ID
+};
+
+static int cts_get_data_info(int op_code, int field, int index, contact_t *contact)
+{
+       int ret, datatype, len;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       switch (op_code)
+       {
+       case CTS_GET_DATA_BY_CONTACT_ID:
+               len = snprintf(query, sizeof(query), "SELECT datatype, id, data1, data2,"
+                               "data3, data4, data5, data6, data7, data8, data9, data10 "
+                               "FROM %s WHERE contact_id = %d", CTS_TABLE_DATA, index);
+               break;
+       case CTS_GET_DATA_BY_ID:
+       default:
+               ERR("Invalid parameter : The op_code(%d) is not supported", op_code);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       if (CTS_DATA_FIELD_ALL != field && CTS_DATA_FIELD_EXTEND_ALL != field)
+       {
+               bool first= true;
+               len += snprintf(query+len, sizeof(query)-len, " AND datatype IN (");
+
+               if (field & CTS_DATA_FIELD_NAME) {
+                       first=false;
+                       len += snprintf(query+len, sizeof(query)-len, "%d", CTS_DATA_NAME);
+               }
+               if (field & CTS_DATA_FIELD_EVENT) {
+                       if (first)
+                               first=false;
+                       else
+                               len += snprintf(query+len, sizeof(query)-len, ", ");
+                       len += snprintf(query+len, sizeof(query)-len, "%d", CTS_DATA_EVENT);
+               }
+               if (field & CTS_DATA_FIELD_MESSENGER) {
+                       if (first)
+                               first=false;
+                       else
+                               len += snprintf(query+len, sizeof(query)-len, ", ");
+                       len += snprintf(query+len, sizeof(query)-len, "%d", CTS_DATA_MESSENGER);
+               }
+               if (field & CTS_DATA_FIELD_POSTAL) {
+                       if (first)
+                               first=false;
+                       else
+                               len += snprintf(query+len, sizeof(query)-len, ", ");
+                       len += snprintf(query+len, sizeof(query)-len, "%d", CTS_DATA_POSTAL);
+               }
+               if (field & CTS_DATA_FIELD_WEB) {
+                       if (first)
+                               first=false;
+                       else
+                               len += snprintf(query+len, sizeof(query)-len, ", ");
+                       len += snprintf(query+len, sizeof(query)-len, "%d", CTS_DATA_WEB);
+               }
+               if (field & CTS_DATA_FIELD_NICKNAME) {
+                       if (first)
+                               first=false;
+                       else
+                               len += snprintf(query+len, sizeof(query)-len, ", ");
+                       len += snprintf(query+len, sizeof(query)-len, "%d", CTS_DATA_NICKNAME);
+               }
+               if (field & CTS_DATA_FIELD_COMPANY) {
+                       if (first)
+                               first=false;
+                       else
+                               len += snprintf(query+len, sizeof(query)-len, ", ");
+                       len += snprintf(query+len, sizeof(query)-len, "%d", CTS_DATA_COMPANY);
+               }
+               if (field & CTS_DATA_FIELD_NUMBER) {
+                       if (first)
+                               first=false;
+                       else
+                               len += snprintf(query+len, sizeof(query)-len, ", ");
+                       len += snprintf(query+len, sizeof(query)-len, "%d", CTS_DATA_NUMBER);
+               }
+               if (field & CTS_DATA_FIELD_EMAIL) {
+                       if (first)
+                               first=false;
+                       else
+                               len += snprintf(query+len, sizeof(query)-len, ", ");
+                       len += snprintf(query+len, sizeof(query)-len, "%d", CTS_DATA_EMAIL);
+               }
+
+               len += snprintf(query+len, sizeof(query)-len, ")");
+       }
+
+       if (CTS_DATA_FIELD_ALL != field && field & CTS_DATA_FIELD_EXTEND_ALL) {
+               len += snprintf(query+len, sizeof(query)-len, " AND datatype>=%d",
+                               CTS_DATA_EXTEND_START);
+       }
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_DB_RECORD_NOT_FOUND;
+       }
+
+       do {
+               datatype = cts_stmt_get_int(stmt, 0);
+
+               switch (datatype)
+               {
+               case CTS_DATA_NAME:
+                       if (contact->name)
+                               ERR("name already Exist");
+                       else
+                               contact->name = cts_get_data_info_name(stmt);
+                       break;
+               case CTS_DATA_EVENT:
+                       cts_get_data_info_event(stmt, contact);
+                       break;
+               case CTS_DATA_MESSENGER:
+                       cts_get_data_info_messenger(stmt, contact);
+                       break;
+               case CTS_DATA_POSTAL:
+                       cts_get_data_info_postal(stmt, contact);
+                       break;
+               case CTS_DATA_WEB:
+                       cts_get_data_info_web(stmt, contact);
+                       break;
+               case CTS_DATA_NICKNAME:
+                       cts_get_data_info_nick(stmt, contact);
+                       break;
+               case CTS_DATA_NUMBER:
+                       cts_get_data_info_number(stmt, contact);
+                       break;
+               case CTS_DATA_EMAIL:
+                       cts_get_data_info_email(stmt, contact);
+                       break;
+               case CTS_DATA_COMPANY:
+                       if (contact->company)
+                               ERR("company already Exist");
+                       else
+                               contact->company = cts_get_data_info_company(stmt);
+                       break;
+               default:
+                       if (CTS_DATA_EXTEND_START <= datatype) {
+                               cts_get_data_info_extend(stmt, datatype, contact);
+                               break;
+                       }
+                       ERR("Unknown data type(%d)", datatype);
+                       continue;
+               }
+       }while(CTS_TRUE == cts_stmt_step(stmt));
+
+       cts_stmt_finalize(stmt);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_get_groups_info(int index, contact_t *contact)
+{
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+       GSList *result_list=NULL;
+
+       snprintf(query, sizeof(query), "SELECT group_id, addrbook_id,"
+                       " group_name"
+                       " FROM %s WHERE group_id IN (SELECT group_id"
+                       " FROM %s WHERE contact_id = %d)"
+                       " ORDER BY group_name COLLATE NOCASE",
+                       CTS_TABLE_GROUPS, CTS_TABLE_GROUPING_INFO, index);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       while (CTS_TRUE == cts_stmt_step(stmt))
+       {
+               cts_group *group_info;
+               group_info = (cts_group *)contacts_svc_value_new(CTS_VALUE_GROUP_RELATION);
+
+               if (group_info)
+               {
+                       group_info->id = cts_stmt_get_int(stmt, 0);
+                       group_info->addrbook_id = cts_stmt_get_int(stmt, 1);
+                       group_info->embedded = true;
+                       group_info->name = SAFE_STRDUP(cts_stmt_get_text(stmt, 2));
+
+                       result_list = g_slist_append(result_list, group_info);
+               }
+       }
+
+       cts_stmt_finalize(stmt);
+       contact->grouprelations = result_list;
+
+       return CTS_SUCCESS;
+
+}
+
+static inline int cts_get_number_value(int op_code, int id, CTSvalue **value)
+{
+       int ret;
+       cts_stmt stmt;
+       cts_number *number;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       if (CTS_GET_DEFAULT_NUMBER_VALUE == op_code) {
+               snprintf(query, sizeof(query),
+                               "SELECT B.id, B.data1, B.data2 FROM %s A, %s B "
+                               "WHERE A.contact_id = %d AND B.id=A.default_num AND B.datatype = %d",
+                               CTS_TABLE_CONTACTS, CTS_TABLE_DATA, id, CTS_DATA_NUMBER);
+       }
+       else if (CTS_GET_NUMBER_VALUE == op_code) {
+               snprintf(query, sizeof(query),
+                               "SELECT id, data1, data2, contact_id FROM %s "
+                               "WHERE id = %d AND datatype = %d",
+                               CTS_TABLE_DATA, id, CTS_DATA_NUMBER);
+       }
+       else {
+               ERR("Invalid op_code(%d)", op_code);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_DB_RECORD_NOT_FOUND;
+       }
+
+       number = (cts_number *)contacts_svc_value_new(CTS_VALUE_NUMBER);
+       if (number) {
+               ret = CTS_SUCCESS;
+               number->v_type = CTS_VALUE_RDONLY_NUMBER;
+               number->embedded = true;
+               cts_stmt_get_number(stmt, number, 0);
+
+               if (CTS_GET_DEFAULT_NUMBER_VALUE == op_code)
+                       number->is_default = true;
+               else
+                       ret = cts_stmt_get_int(stmt, 3);
+
+               *value = (CTSvalue*) number;
+
+               cts_stmt_finalize(stmt);
+               return ret;
+       }
+       else {
+               ERR("contacts_svc_value_new() Failed");
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_OUT_OF_MEMORY;
+       }
+}
+
+static inline int cts_get_email_value(int op_code, int id, CTSvalue **value)
+{
+       int ret;
+       cts_stmt stmt;
+       cts_email *email;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       if (CTS_GET_DEFAULT_EMAIL_VALUE == op_code) {
+               snprintf(query, sizeof(query),
+                               "SELECT B.id, B.data1, B.data2 FROM %s A, %s B "
+                               "WHERE A.contact_id = %d AND B.id=A.default_email AND B.datatype = %d",
+                               CTS_TABLE_CONTACTS, CTS_TABLE_DATA, id, CTS_DATA_EMAIL);
+       }
+       else if (CTS_GET_EMAIL_VALUE == op_code) {
+               snprintf(query, sizeof(query),
+                               "SELECT id, data1, data2, contact_id FROM %s "
+                               "WHERE id = %d AND datatype = %d",
+                               CTS_TABLE_DATA, id, CTS_DATA_EMAIL);
+       }
+       else {
+               ERR("Invalid op_code(%d)", op_code);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_DB_RECORD_NOT_FOUND;
+       }
+
+       email = (cts_email *)contacts_svc_value_new(CTS_VALUE_EMAIL);
+       if (email)
+       {
+               ret = CTS_SUCCESS;
+               email->v_type = CTS_VALUE_RDONLY_EMAIL;
+               email->embedded = true;
+               cts_stmt_get_email(stmt, email, 0);
+
+               if (CTS_GET_DEFAULT_EMAIL_VALUE == op_code)
+                       email->is_default = true;
+               else
+                       ret = cts_stmt_get_int(stmt, 3);
+
+               *value = (CTSvalue*) email;
+
+               cts_stmt_finalize(stmt);
+               return ret;
+       }
+       else
+       {
+               ERR("contacts_svc_value_new() Failed");
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_OUT_OF_MEMORY;
+       }
+}
+
+static inline int cts_get_extend_data(int type, int id, CTSvalue **value)
+{
+       int ret;
+       cts_stmt stmt;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       snprintf(query, sizeof(query), "SELECT id, data1, data2,"
+                       "data3, data4, data5, data6, data7, data8, data9, data10 "
+                       "FROM %s WHERE datatype = %d AND contact_id = %d", CTS_TABLE_DATA, type, id);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_DB_RECORD_NOT_FOUND;
+       }
+
+       *value = (CTSvalue *)cts_make_extend_data(stmt, type, 0);
+       cts_stmt_finalize(stmt);
+
+       retvm_if(NULL == *value, CTS_ERR_OUT_OF_MEMORY, "cts_make_extend_data() return NULL");
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_get_contact_value(cts_get_contact_val_op op_code,
+               int id, CTSvalue **value)
+{
+       int ret;
+       contact_t temp={0};
+
+       retv_if(NULL == value, CTS_ERR_ARG_NULL);
+       CTS_START_TIME_CHECK;
+
+       if ((int)CTS_DATA_EXTEND_START <= op_code) {
+               ret = cts_get_extend_data(op_code, id, value);
+               retvm_if(CTS_SUCCESS != ret, ret, "cts_get_extend_data() Failed(%d)", ret);
+       }
+       else {
+               switch (op_code)
+               {
+               case CTS_GET_NAME_VALUE:
+                       ret = cts_get_data_info(CTS_GET_DATA_BY_CONTACT_ID,
+                                       CTS_DATA_FIELD_NAME, id, &temp);
+                       retvm_if(CTS_SUCCESS != ret, ret,
+                                       "cts_get_data_info(CTS_GET_DATA_BY_CONTACT_ID) Failed(%d)", ret);
+                       if (temp.name) {
+                               temp.name->v_type = CTS_VALUE_RDONLY_NAME;
+                               *value = (CTSvalue *)temp.name;
+                       }else
+                               *value = NULL;
+                       break;
+               case CTS_GET_DEFAULT_NUMBER_VALUE:
+               case CTS_GET_NUMBER_VALUE:
+                       ret = cts_get_number_value(op_code, id, value);
+                       retvm_if(ret < CTS_SUCCESS, ret,
+                                       "cts_get_number_value() Failed(%d)", ret);
+                       break;
+               case CTS_GET_DEFAULT_EMAIL_VALUE:
+               case CTS_GET_EMAIL_VALUE:
+                       ret = cts_get_email_value(op_code, id, value);
+                       retvm_if(ret < CTS_SUCCESS, ret, "cts_get_email_value() Failed(%d)", ret);
+                       break;
+               case CTS_GET_COMPANY_VALUE:
+                       ret = cts_get_data_info(CTS_GET_DATA_BY_CONTACT_ID,
+                                       CTS_DATA_FIELD_COMPANY, id, &temp);
+                       retvm_if(CTS_SUCCESS != ret, ret,
+                                       "cts_get_data_info(CTS_DATA_FIELD_COMPANY) Failed(%d)", ret);
+                       if (temp.company) {
+                               temp.company->v_type = CTS_VALUE_RDONLY_COMPANY;
+                               *value = (CTSvalue *)temp.company;
+                       }else
+                               *value = NULL;
+                       break;
+               default:
+                       ERR("Invalid parameter : The op_code(%d) is not supported", op_code);
+                       return CTS_ERR_ARG_INVALID;
+               }
+       }
+       if (NULL == *value) return CTS_ERR_NO_DATA;
+
+       CTS_END_TIME_CHECK();
+       return ret;
+}
+
+API int contacts_svc_get_contact(int index, CTSstruct **contact)
+{
+       int ret;
+       contact_t *record;
+
+       retv_if(NULL == contact, CTS_ERR_ARG_NULL);
+       CTS_START_TIME_CHECK;
+
+       record = (contact_t *)contacts_svc_struct_new(CTS_STRUCT_CONTACT);
+
+       ret = cts_get_main_contacts_info(CTS_MAIN_CTS_GET_ALL, index, record);
+
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_get_main_contacts_info(ALL) Failed(%d)", ret);
+               goto CTS_RETURN_ERROR;
+       }
+
+       ret = cts_get_data_info(CTS_GET_DATA_BY_CONTACT_ID,
+                       CTS_DATA_FIELD_ALL, index, record);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_get_data_info(CTS_GET_DATA_BY_CONTACT_ID) Failed(%d)", ret);
+               goto CTS_RETURN_ERROR;
+       }
+
+       ret = cts_get_groups_info(index, record);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_get_group_info(CTS_GET_DATA_BY_CONTACT_ID) Failed(%d)", ret);
+               goto CTS_RETURN_ERROR;
+       }
+
+       *contact = (CTSstruct *)record;
+
+       CTS_END_TIME_CHECK();
+       return CTS_SUCCESS;
+
+CTS_RETURN_ERROR:
+       contacts_svc_struct_free((CTSstruct *)record);
+       return ret;
+}
+
+API int contacts_svc_find_contact_by(cts_find_op op_code,
+               const char *user_data)
+{
+       int ret;
+       const char *temp;
+       char query[CTS_SQL_MAX_LEN] = {0};
+       char normalized_val[CTS_SQL_MIN_LEN];
+
+       CTS_START_TIME_CHECK;
+       retv_if(NULL == user_data, CTS_ERR_ARG_NULL);
+
+       switch (op_code)
+       {
+       case CTS_FIND_BY_NUMBER:
+               ret = cts_clean_number(user_data, normalized_val, sizeof(normalized_val));
+               retvm_if(ret <= 0, CTS_ERR_ARG_INVALID, "Number(%s) is invalid", user_data);
+
+               temp = cts_normalize_number(normalized_val);
+               snprintf(query, sizeof(query), "SELECT contact_id "
+                               "FROM %s WHERE datatype = %d AND data3 = '%s' LIMIT 1",
+                               CTS_TABLE_DATA, CTS_DATA_NUMBER, temp);
+               ret = cts_query_get_first_int_result(query);
+               break;
+       case CTS_FIND_BY_EMAIL:
+               snprintf(query, sizeof(query), "SELECT contact_id "
+                               "FROM %s WHERE datatype = %d AND data2 = '%s' LIMIT 1",
+                               CTS_TABLE_DATA, CTS_DATA_EMAIL, user_data);
+               ret = cts_query_get_first_int_result(query);
+               break;
+       case CTS_FIND_BY_NAME:
+               ret = cts_normalize_str(user_data, normalized_val, sizeof(normalized_val));
+               retvm_if(ret < CTS_SUCCESS, ret, "cts_normalize_str() Failed(%d)", ret);
+
+               if (CTS_ORDER_NAME_LASTFIRST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       temp = CTS_SCHEMA_DATA_NAME_REVERSE_LOOKUP;
+               else
+                       temp = CTS_SCHEMA_DATA_NAME_LOOKUP;
+
+               snprintf(query, sizeof(query), "SELECT contact_id FROM %s "
+                               "WHERE %s LIKE '%%%s%%' LIMIT 1",
+                               CTS_TABLE_DATA, temp, normalized_val);
+
+               ret = cts_query_get_first_int_result(query);
+               break;
+       case CTS_FIND_BY_UID:
+               snprintf(query, sizeof(query), "SELECT contact_id "
+                               "FROM %s WHERE uid = '%s' LIMIT 1", CTS_TABLE_CONTACTS, user_data);
+               ret = cts_query_get_first_int_result(query);
+               break;
+       default:
+               ERR("Invalid parameter : The op_code(%d) is not supported", op_code);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       CTS_END_TIME_CHECK();
+       return ret;
+}
diff --git a/src/cts-contact.h b/src/cts-contact.h
new file mode 100755 (executable)
index 0000000..85b1a2b
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_CONTACT_H__
+#define __CTS_CONTACT_H__
+
+//<!--
+/**
+ * @defgroup   CONTACTS_SVC_NAME Contact Naming Rule
+ * @ingroup    CONTACTS_SVC
+ * @addtogroup CONTACTS_SVC_NAME
+ * @{
+ * - insert
+ * @code
+ * if (No Name) {
+ *     if (Has "Company Name")
+ *             Display Name = "Company Name";
+ *     else if (Has "Number")
+ *             Display Name = "Number";
+ *     else if (Has "E-mail")
+ *             Display Name = "E-mail";
+ * }
+ * @endcode
+ *
+ * - update
+ * @code
+ * if (No "First Name" & No "Last Name") {
+ *     if (Has "Company Name")
+ *             Display Name = "Company Name";
+ *     else if (Has "Number")
+ *             Display Name = "Number";
+ *     else if (Has "E-mail")
+ *             Display Name = "E-mail";
+ * }
+ * @endcode
+ * @}
+ */
+
+/**
+ * @defgroup   CONTACTS_SVC_CONTACT Contact information Modification
+ * @ingroup    CONTACTS_SVC
+ * @addtogroup CONTACTS_SVC_CONTACT
+ * @{
+ *
+ * This interface provides methods to insert/update/delete the Contact information.
+ *
+ */
+
+/**
+ * This function inserts a contact into database.
+ * This api assigns a index of the contact automatically.
+ * \n The returned index is unique and non-reusable.
+ *
+ * @param[in] addressbook_id The index of addressbook. 0 is local(phone internal)
+ * @param[in] contact A contact information of CTSstruct() created by contacts_svc_struct_new(CTS_STRUCT_CONTACT).
+ * @return the index of contact on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void insert_test(void)
+ {
+    CTSstruct *contact;
+    CTSvalue *name, *number1, *number2;
+    GSList *numbers=NULL;
+    contact = contacts_svc_struct_new(CTS_STRUCT_CONTACT);
+
+    name = contacts_svc_value_new(CTS_VALUE_NAME);
+    if(name) {
+       contacts_svc_value_set_str(name, CTS_NAME_VAL_FIRST_STR, "gildong");
+       contacts_svc_value_set_str(name, CTS_NAME_VAL_LAST_STR, "Hong");
+       contacts_svc_value_set_str(name, CTS_NAME_VAL_SUFFIX_STR, "engineer");
+    }
+    contacts_svc_struct_store_value(contact, CTS_CF_NAME_VALUE, name);
+    contacts_svc_value_free(name);
+
+    number1 = contacts_svc_value_new(CTS_VALUE_NUMBER);
+    if(number1) {
+       contacts_svc_value_set_str(number1, CTS_NUM_VAL_NUMBER_STR, "0987654321");
+       contacts_svc_value_set_int(number1, CTS_NUM_VAL_TYPE_INT, CTS_NUM_TYPE_CELL);
+       contacts_svc_value_set_bool(number1, CTS_NUM_VAL_DEFAULT_BOOL, true);
+    }
+    numbers = g_slist_append(numbers, number1);
+
+    number2 = contacts_svc_value_new(CTS_VALUE_NUMBER);
+    if(number2) {
+       contacts_svc_value_set_str(number2, CTS_NUM_VAL_NUMBER_STR, "0123456789");
+       contacts_svc_value_set_int(number2, CTS_NUM_VAL_TYPE_INT,
+                                  CTS_NUM_TYPE_BUSINESS|CTS_NUM_TYPE_FAX);
+    }
+    numbers = g_slist_append(numbers, number2);
+
+    contacts_svc_struct_store_list(contact, CTS_CF_NUMBER_LIST, numbers);
+    contacts_svc_value_free(number1);
+    contacts_svc_value_free(number2);
+    g_slist_free(numbers);
+
+    contacts_svc_insert_contact(0, contact);
+    contacts_svc_struct_free(contact);
+ }
+ * @endcode
+ */
+int contacts_svc_insert_contact(int addressbook_id, CTSstruct* contact);
+
+/**
+ * This function deletes a contact in database.
+ * It is not only deletes contact records from contact table,
+ * but also clears up all the info of these contacts(group relation info, favorites info and etc.).
+ *
+ * @param[in] index The index of contact to delete in database.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void delete_test(void)
+ {
+    //get contact
+    //CTSstruct *contact;
+    //contacts_svc_struct_get_value(contact, CTS_CF_INDEX_INT, &value);
+    //int index = contacts_svc_value_get_int(value, CTS_BASIC_VAL_INT);
+
+    contacts_svc_delete_contact(2);
+
+    //contacts_svc_struct_free(contact);
+
+#if DELETE_CONTACTS
+    // TODO: get each index of contacts
+    int i, index_list[10] ={1,3,4,65,345,54,5,2,9,10};
+    int ret;
+
+    ret = contacts_svc_begin_trans();
+    if(CTS_SUCCESS != ret) return;
+    for(i=0;i<10;i++) {
+       ret = contacts_svc_delete_contact(index_list[i]);
+       if(CTS_SUCCESS != ret) {
+          contacts_svc_end_trans(false);
+          return;
+       }
+    }
+    ret = contacts_svc_end_trans(true);
+    if(ret < CTS_SUCCESS){
+       printf("all work were rollbacked");
+       return;
+    }
+#endif
+ }
+ * @endcode
+ */
+int contacts_svc_delete_contact(int index);
+
+/**
+ * This function updates a contact in the database.
+ * \n If you want to add to list, store list.(refer to example)
+ * \n To remove from list, set the value's VAL_DELETE_BOOL field.
+ *
+ * @param[in] contact A contact information of #CTSstruct.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+
+ void update_test()
+ {
+    GSList *numbers, *cursor;
+    CTSvalue *number=NULL;
+    CTSstruct *contact=NULL;
+
+    contacts_svc_get_contact(1, &contact);
+
+    numbers = NULL;
+    contacts_svc_struct_get_list(contact, CTS_CF_NUMBER_LIST, &numbers);
+    cursor = numbers;
+    if(cursor) {
+       //char *temp = contacts_svc_value_get_str(cursor->data, CTS_NUM_VAL_NUMBER_STR);
+       contacts_svc_value_set_str(cursor->data, CTS_NUM_VAL_NUMBER_STR, "0987651234");
+
+       cursor = g_slist_next(cursor);
+       if(cursor)
+          contacts_svc_value_set_bool(cursor->data, CTS_NUM_VAL_DELETE_BOOL, true);
+
+       number = contacts_svc_value_new(CTS_VALUE_NUMBER);
+       if(number) {
+          contacts_svc_value_set_str(number, CTS_NUM_VAL_NUMBER_STR, "0125439876");
+          contacts_svc_value_set_int(number, CTS_NUM_VAL_TYPE_INT, CTS_NUM_TYPE_CELL);
+          contacts_svc_value_set_bool(number, CTS_NUM_VAL_DEFAULT_BOOL, true);
+       }
+       numbers = g_slist_append(numbers, number);
+    }
+
+    contacts_svc_struct_store_list(contact, CTS_CF_NUMBER_LIST, numbers);
+    contacts_svc_value_free(number);
+    //free("0125439876");
+    contacts_svc_update_contact(contact);
+
+    contacts_svc_struct_free(contact);
+ }
+ * @endcode
+ */
+int contacts_svc_update_contact(CTSstruct* contact);
+
+/**
+ * Use for contacts_svc_put_contact_value().
+ */
+typedef enum{
+       CTS_PUT_VAL_REPLACE_RINGTONE=0,/**< Use #CTS_VALUE_CONTACT_BASE_INFO */
+       CTS_PUT_VAL_REPLACE_NOTE=2,/**< Use #CTS_VALUE_CONTACT_BASE_INFO */
+       CTS_PUT_VAL_ADD_NUMBER=3,/**< Use #CTS_VALUE_NUMBER */
+       CTS_PUT_VAL_ADD_EMAIL=4,/**< Use #CTS_VALUE_EMAIL */
+}cts_put_contact_val_op;
+
+/**
+ * This function puts contacts service value(#CTSvalue) with op_code(#cts_put_contact_val_op).
+ *
+ * @param[in] op_code #cts_put_contact_val_op
+ * @param[in] contact_id The index of the contact to put value.
+ * @param[in] value The contacts service value which is put.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void put_value_test()
+ {
+    CTSvalue *value, *number;
+
+    value = contacts_svc_value_new(CTS_VALUE_CONTACT_BASE_INFO);
+    if(value) {
+       contacts_svc_value_set_str(value, CTS_BASE_VAL_RINGTONE_PATH_STR,
+                                  "/opt/test/test.mp3");
+       contacts_svc_put_contact_value(CTS_PUT_VAL_REPLACE_RINGTONE, 1, value);
+       contacts_svc_value_free(value);
+       //free("/opt/test/test.mp3")
+    }
+
+    number = contacts_svc_value_new(CTS_VALUE_NUMBER);
+    if(number) {
+       contacts_svc_value_set_str(number, CTS_NUM_VAL_NUMBER_STR, "0123337777");
+       contacts_svc_value_set_int(number, CTS_NUM_VAL_TYPE_INT, CTS_NUM_TYPE_CELL);
+       contacts_svc_value_set_bool(number, CTS_NUM_VAL_DEFAULT_BOOL, true);
+
+       contacts_svc_put_contact_value(CTS_PUT_VAL_ADD_NUMBER, 1, number);
+       contacts_svc_value_free(number);
+       //free("0123337777")
+    }
+ }
+ * @endcode
+ */
+int contacts_svc_put_contact_value(cts_put_contact_val_op op_code,
+               int contact_id, CTSvalue* value);
+
+
+/**
+ * Use for contacts_svc_get_contact_value().
+ */
+typedef enum {
+       CTS_GET_NAME_VALUE, /**< Use #NAMEVALUE */
+       CTS_GET_DEFAULT_EMAIL_VALUE,/**< related with contact id. Use #EMAILVALUE */
+       CTS_GET_DEFAULT_NUMBER_VALUE,/**< related with contact id. Use #NUMBERVALUE */
+       CTS_GET_NUMBER_VALUE, /**< related with number id. Use #NUMBERVALUE */
+       CTS_GET_EMAIL_VALUE, /**< related with email id. Use #EMAILVALUE */
+       CTS_GET_COMPANY_VALUE, /**< related with contact id. Use #COMPANYVALUE */
+}cts_get_contact_val_op;
+/**
+ * This function can get a value data related with id and op_code.
+ * The value data is decided by op_code(#cts_get_contact_val_op)
+ * The gotten value is readonly.
+ * If id is not contact id, it returns the related contact id.
+ * Obtained contact record should be freed by using contacts_svc_value_free().
+ * @return #CTS_SUCCESS or the related contact id on success, Negative value(#cts_error) on error
+ * @param[in] op_code #cts_get_contact_val_op
+ * @param[in] id The related index
+ * @param[out] value Points of the contacts service value(#CTSvalue) which is returned
+ * @par example
+ * @code
+ void get_contact_default_num(void)
+ {
+    int index, ret;
+    CTSvalue *number=NULL;
+    const char *default_num;
+
+    index = contacts_svc_find_contact_by(CTS_FIND_BY_NUMBER, "0125439876");
+
+    ret = contacts_svc_get_contact_value(CTS_GET_DEFAULT_NUMBER_VALUE, index, &number);
+    if(ret < CTS_SUCCESS) {
+       printf("contacts_svc_get_contact_value() Failed(%d)\n", ret);
+       return;
+    }
+
+    default_num = contacts_svc_value_get_str(number, CTS_NUM_VAL_NUMBER_STR);
+    printf("The default Number is %s\n", default_num);
+    contacts_svc_value_free(number);
+ }
+ * @endcode
+ */
+int contacts_svc_get_contact_value(cts_get_contact_val_op op_code,
+               int id, CTSvalue **value);
+
+
+/**
+ * This function gets contact record which has the index from the database.
+ * Obtained contact record should be freed by using contacts_svc_struct_free().
+ * @param[in] index The index of contact to get
+ * @param[out] contact Points of the contact record which is returned
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void get_contact(void)
+ {
+    int ret=-1;
+    CTSstruct *contact = NULL;
+    CTSvalue *name;
+    GSList *get_list, *cursor;
+
+    ret = contacts_svc_get_contact(1, &contact);
+    if(ret < 0)
+    {
+       printf("No found record\n");
+       return;
+    }
+
+    contacts_svc_struct_get_value(contact, CTS_CF_NAME_VALUE, &name);
+    printf("First Name : %s\n", contacts_svc_value_get_str(name, CTS_NAME_VAL_FIRST_STR));
+    printf("Last Name : %s\n", contacts_svc_value_get_str(name, CTS_NAME_VAL_LAST_STR));
+    printf("Additional Name : %s\n", contacts_svc_value_get_str(name, CTS_NAME_VAL_ADDITION_STR));
+    printf("Display Name : %s\n", contacts_svc_value_get_str(name, CTS_NAME_VAL_DISPLAY_STR));
+    printf("Prefix Name : %s\n", contacts_svc_value_get_str(name, CTS_NAME_VAL_PREFIX_STR));
+    printf("Suffix Name : %s\n", contacts_svc_value_get_str(name, CTS_NAME_VAL_SUFFIX_STR));
+
+    get_list = NULL;
+    contacts_svc_struct_get_list(contact, CTS_CF_NUMBER_LIST, &get_list);
+
+    cursor = get_list;
+    for(;cursor;cursor=g_slist_next(cursor))
+    {
+       printf("number Type = %d",
+          contacts_svc_value_get_int(cursor->data, CTS_NUM_VAL_TYPE_INT));
+
+       printf("Number = %s\n",
+          contacts_svc_value_get_str(cursor->data, CTS_NUM_VAL_NUMBER_STR));
+    }
+
+    get_list = NULL;
+    contacts_svc_struct_get_list(contact, CTS_CF_EMAIL_LIST, &get_list);
+
+    cursor = get_list;
+    for(;cursor;cursor=g_slist_next(cursor))
+    {
+       printf("email Type = %d",
+          contacts_svc_value_get_int(cursor->data, CTS_EMAIL_VAL_TYPE_INT));
+
+       printf("email = %s\n",
+          contacts_svc_value_get_str(cursor->data, CTS_EMAIL_VAL_ADDR_STR));
+    }
+
+    contacts_svc_struct_free(contact);
+ }
+ * @endcode
+ */
+int contacts_svc_get_contact(int index, CTSstruct **contact);
+
+/**
+ * Use for contacts_svc_find_contact_by().
+ */
+typedef enum {
+       CTS_FIND_NONE,
+       CTS_FIND_BY_NAME,
+       CTS_FIND_BY_NUMBER,
+       CTS_FIND_BY_EMAIL,
+       CTS_FIND_BY_UID,
+}cts_find_op;
+/**
+ * This function gets index of contact related with user_data.
+ * index is found by op_code with user_data related with op_code(#cts_find_op).
+ * @param[in] op_code #cts_find_op
+ * @param[in] user_data The parameter for searching
+ * @return index of found contact on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void get_contact(void)
+ {
+    int index, ret=-1;
+    CTSstruct *contact = NULL;
+
+    index = contacts_svc_find_contact_by(CTS_FIND_BY_NUMBER, "0123456789");
+    if(index > CTS_SUCCESS)
+      ret = contacts_svc_get_contact(index, &contact);
+    if(ret < 0)
+    {
+       printf("No found record\n");
+       return;
+    }
+ }
+ * @endcode
+ */
+int contacts_svc_find_contact_by(cts_find_op op_code, const char *user_data);
+
+/**
+ * @}
+ */
+
+//-->
+#endif //__CTS_CONTACT_H__
+
diff --git a/src/cts-errors.h b/src/cts-errors.h
new file mode 100755 (executable)
index 0000000..55a2c9a
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_ERRORS_H__
+#define __CTS_ERRORS_H__
+
+//<!--
+typedef enum
+{
+       CTS_ERR_DB_LOCK = -204, /**< -204 */
+       CTS_ERR_DB_RECORD_NOT_FOUND = -203, /**< -203 */
+       CTS_ERR_DB_FAILED = -202, /**< -202 */
+       CTS_ERR_DB_NOT_OPENED= -201, /**< -201 */
+
+       CTS_ERR_ICU_FAILED = -106, /**< -106 */
+       CTS_ERR_TAPI_FAILED = -105, /**< -105 */
+       CTS_ERR_SOCKET_FAILED = -104, /**< -104 */
+       CTS_ERR_INOTIFY_FAILED = -103, /**< -103 */
+       CTS_ERR_VCONF_FAILED = -102, /**< -102 */
+       CTS_ERR_VOBJECT_FAILED = -101, /**< -101 */
+
+       CTS_ERR_NO_SPACE = -13, /**< -13 */
+       CTS_ERR_IO_ERR = -12, /**< -12 */
+       CTS_ERR_MSG_INVALID = -11, /**< -11 */
+       CTS_ERR_ALREADY_RUNNING = -10, /**< -10 */
+       CTS_ERR_EXCEEDED_LIMIT = -9, /**< -9 */
+       CTS_ERR_OUT_OF_MEMORY = -8, /**< -8 */
+       CTS_ERR_ALREADY_EXIST = -7, /**< -7 */
+       CTS_ERR_ENV_INVALID = -6, /**< -6 */
+       CTS_ERR_ARG_NULL = -5, /**< -5 */
+       CTS_ERR_ARG_INVALID = -4, /**< -4 */
+       CTS_ERR_NO_DATA = -3, /**< -3 */
+       CTS_ERR_FINISH_ITER= -2, /**< -2 */
+       CTS_ERR_FAIL= -1, /**< -1 */
+       CTS_SUCCESS = 0, /**< 0 */
+       CTS_FALSE = 0, /**< 0 */
+       CTS_TRUE = 1 /**< 1 */
+}cts_error;
+//-->
+
+#endif //__CTS_ERRORS_H__
+
diff --git a/src/cts-favorite.c b/src/cts-favorite.c
new file mode 100755 (executable)
index 0000000..c2d2655
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "cts-internal.h"
+#include "cts-schema.h"
+#include "cts-sqlite.h"
+#include "cts-utils.h"
+#include "cts-favorite.h"
+
+API int contacts_svc_set_favorite(cts_favor_type op, int related_id)
+{
+       int ret;
+       double prio = 0.0;
+       cts_stmt stmt;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       retvm_if(CTS_FAVOR_CONTACT != op && CTS_FAVOR_NUMBER != op, CTS_ERR_ARG_INVALID,
+                       "op(%d) is invalid", op);
+
+       snprintf(query, sizeof(query),
+                       "SELECT MAX(favorite_prio) FROM %s", CTS_TABLE_FAVORITES);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE == ret) {
+               prio = cts_stmt_get_dbl(stmt, 0);
+       }
+       else if (CTS_SUCCESS != ret) {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       cts_stmt_finalize(stmt);
+
+       prio = prio + 1.0;
+       snprintf(query, sizeof(query),
+                       "INSERT INTO %s(type, related_id, favorite_prio) VALUES(%d, %d, %f)",
+                       CTS_TABLE_FAVORITES, op, related_id, prio);
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       cts_set_favor_noti();
+
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_unset_favorite(cts_favor_type op, int related_id)
+{
+       int ret;
+       cts_stmt stmt;
+       char query[CTS_SQL_MIN_LEN] = {0};
+
+       retvm_if(CTS_FAVOR_CONTACT != op && CTS_FAVOR_NUMBER != op, CTS_ERR_ARG_INVALID,
+                       "op(%d) is invalid", op);
+
+       snprintf(query, sizeof(query), "DELETE FROM %s WHERE type = %d AND related_id = %d",
+                       CTS_TABLE_FAVORITES, op, related_id);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = contacts_svc_begin_trans();
+       if (ret) {
+               cts_stmt_finalize(stmt);
+               ERR("contacts_svc_begin_trans() Failed(%d)", ret);
+               return ret;
+       }
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       ret = cts_db_change();
+       cts_stmt_finalize(stmt);
+
+       if (0 < ret) {
+               cts_set_favor_noti();
+               ret = contacts_svc_end_trans(true);
+       }
+       else {
+               contacts_svc_end_trans(false);
+               ret = CTS_ERR_NO_DATA;
+       }
+
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_delete_favorite(int favorite_id)
+{
+       int ret;
+       cts_stmt stmt;
+       char query[CTS_SQL_MIN_LEN] = {0};
+
+       snprintf(query, sizeof(query), "DELETE FROM %s WHERE id = %d",
+                       CTS_TABLE_FAVORITES, favorite_id);
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       ret = cts_db_change();
+       cts_stmt_finalize(stmt);
+
+       if (0 < ret) {
+               cts_set_favor_noti();
+               ret = contacts_svc_end_trans(true);
+       }
+       else {
+               contacts_svc_end_trans(false);
+               ret = CTS_ERR_NO_DATA;
+       }
+
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+static inline int cts_modify_favorite_prio(int favorite_id, int front, int back)
+{
+       int ret;
+       cts_stmt stmt;
+       double front_prio=0.0, back_prio=0.0, prio;
+       char query[CTS_SQL_MIN_LEN] = {0};
+
+       snprintf(query, sizeof(query), "SELECT favorite_prio FROM %s WHERE id = ?",
+                       CTS_TABLE_FAVORITES);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       cts_stmt_bind_int(stmt, 1, front);
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE == ret)
+               front_prio = cts_stmt_get_dbl(stmt, 0);
+
+       cts_stmt_reset(stmt);
+       cts_stmt_bind_int(stmt, 1, back);
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE == ret)
+               back_prio = cts_stmt_get_dbl(stmt, 0);
+
+       cts_stmt_finalize(stmt);
+
+       retvm_if(0.0 == front_prio && 0.0 == back_prio, CTS_ERR_ARG_INVALID,
+                       "The indexes for front and back are invalid.");
+
+       if (0.0 == back_prio)
+               prio = front_prio + 1;
+       else
+               prio = (front_prio + back_prio) / 2;
+
+       snprintf(query, sizeof(query),
+                       "UPDATE %s SET favorite_prio = %f WHERE id = %d",
+                       CTS_TABLE_FAVORITES, prio, favorite_id);
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               return ret;
+       }
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_favorite_order(int favorite_id,
+               int front_favorite_id, int back_favorite_id)
+{
+       int ret;
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       ret = cts_modify_favorite_prio(favorite_id, front_favorite_id, back_favorite_id);
+
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_modify_favorite_prio() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       cts_set_favor_noti();
+
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_set_speeddial(int speed_num, int number_id)
+{
+       int ret;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       snprintf(query, sizeof(query),
+                       "INSERT INTO %s(speed_num, number_id) VALUES(%d, %d)",
+                       CTS_TABLE_SPEEDDIALS, speed_num, number_id);
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       cts_set_speed_noti();
+
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_unset_speeddial(int speed_num)
+{
+       int ret;
+       cts_stmt stmt;
+       char query[CTS_SQL_MIN_LEN] = {0};
+
+       snprintf(query, sizeof(query), "DELETE FROM %s WHERE speed_num = %d",
+                       CTS_TABLE_SPEEDDIALS, speed_num);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = contacts_svc_begin_trans();
+       if (ret) {
+               cts_stmt_finalize(stmt);
+               ERR("contacts_svc_begin_trans() Failed(%d)", ret);
+               return ret;
+       }
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       ret = cts_db_change();
+       cts_stmt_finalize(stmt);
+
+       if (0 < ret) {
+               cts_set_speed_noti();
+               ret = contacts_svc_end_trans(true);
+       }
+       else {
+               contacts_svc_end_trans(false);
+               ret = CTS_ERR_NO_DATA;
+       }
+
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_get_speeddial(int speed_num, CTSvalue **value)
+{
+       int ret;
+       cts_stmt stmt;
+       cts_number *number;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       snprintf(query, sizeof(query),
+                       "SELECT A.id, A.data1, A.data2, A.contact_id FROM %s A, %s B "
+                       "WHERE A.datatype = %d AND B.speed_num = %d AND A.id = B.number_id",
+                       CTS_TABLE_DATA, CTS_TABLE_SPEEDDIALS, CTS_DATA_NUMBER, speed_num);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_DB_RECORD_NOT_FOUND;
+       }
+
+       number = (cts_number *)contacts_svc_value_new(CTS_VALUE_NUMBER);
+       if (number) {
+               ret = CTS_SUCCESS;
+               number->v_type = CTS_VALUE_RDONLY_NUMBER;
+               number->embedded = true;
+               number->id = cts_stmt_get_int(stmt, 0);
+               number->type = cts_stmt_get_int(stmt, 1);
+               number->number = SAFE_STRDUP(cts_stmt_get_text(stmt, 2));
+               ret = cts_stmt_get_int(stmt, 3);
+
+               *value = (CTSvalue*) number;
+
+               cts_stmt_finalize(stmt);
+               return ret;
+       }
+       else {
+               ERR("contacts_svc_value_new() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_OUT_OF_MEMORY;
+       }
+}
diff --git a/src/cts-favorite.h b/src/cts-favorite.h
new file mode 100755 (executable)
index 0000000..f62c02f
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_FAVORITE_H__
+#define __CTS_FAVORITE_H__
+
+//<!--
+
+/**
+ * @defgroup   CONTACTS_SVC_FAVORITE Favorite(speeddial) Modification
+ * @ingroup    CONTACTS_SVC
+ * @addtogroup CONTACTS_SVC_FAVORITE
+ * @{
+ *
+ * This interface provides methods to insert/update/delete the Favorite(speeddial).
+ *
+ */
+
+/**
+ * favorite type
+ */
+typedef enum{
+       CTS_FAVOR_CONTACT, /**< Favorite for a contact */
+       CTS_FAVOR_NUMBER /**< Favorite for a number */
+}cts_favor_type;
+
+/**
+ * This function marks a number or a contact as "favorite".
+ * @param[in] op favorite type(#cts_favor_type).
+ * @param[in] related_id a contact or number id which is related op.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_set_favorite(cts_favor_type op, int related_id);
+
+/**
+ * This function unsets a number or a contact to the favorite.
+ * @param[in] op favorite type(#cts_favor_type).
+ * @param[in] related_id a contact or number id which is related op.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_unset_favorite(cts_favor_type op, int related_id);
+
+/**
+ * This function deletes a favorite from favorite list.
+ * @param[in] favorite_id index of favorite.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_delete_favorite(int favorite_id);
+
+/**
+ * This function modifies priority of favorite.
+ * The priority of favorite will be between a front favorite and a back favorite.
+ *
+ * @param[in] favorite_id The index of a favorite data
+ * @param[in] front_favorite_id Id of the front favorite.
+ * @param[in] back_favorite_id Id of the back favorite.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_favorite_order(int favorite_id, int front_favorite_id, int back_favorite_id);
+
+/**
+ * This function sets a number to the speeddial.
+ * @param[in] speed_num speed dial number.
+ * @param[in] number_id the index of number
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_set_speeddial(int speed_num, int number_id);
+
+/**
+ * This function unsets speed dial number.
+ * @param[in] speed_num speed dial number.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_unset_speeddial(int speed_num);
+
+/**
+ * @}
+ */
+
+//-->
+
+#endif //__CTS_FAVORITE_H__
diff --git a/src/cts-group.c b/src/cts-group.c
new file mode 100755 (executable)
index 0000000..808144a
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "cts-internal.h"
+#include "cts-schema.h"
+#include "cts-sqlite.h"
+#include "cts-utils.h"
+#include "cts-list.h"
+#include "cts-group.h"
+
+API int contacts_svc_find_group(int addressbook_id, const char *name)
+{
+       char query[CTS_SQL_MIN_LEN];
+
+       retv_if(NULL == name, CTS_ERR_ARG_NULL);
+
+       snprintf(query, sizeof(query), "SELECT group_id FROM %s "
+                       "WHERE group_name = '%s' LIMIT 1",
+                       CTS_TABLE_GROUPS, name);
+
+       return cts_query_get_first_int_result(query);
+}
+
+
+API int contacts_svc_get_group(int index, CTSvalue **retgroup)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       retv_if(NULL == retgroup, CTS_ERR_ARG_NULL);
+
+       snprintf(query, sizeof(query),
+                       "SELECT group_id, addrbook_id, group_name, ringtone "
+                       "FROM %s WHERE group_id = %d", CTS_TABLE_GROUPS, index);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_DB_RECORD_NOT_FOUND;
+       }
+       cts_group *group;
+       group = (cts_group *)contacts_svc_value_new(CTS_VALUE_GROUP);
+
+       if (group)
+       {
+               group->embedded = true;
+               group->id = cts_stmt_get_int(stmt, 0);
+               group->addrbook_id = cts_stmt_get_int(stmt, 1);
+               group->name = SAFE_STRDUP(cts_stmt_get_text(stmt, 2));
+               group->ringtone_path = SAFE_STRDUP(cts_stmt_get_text(stmt, 3));
+       }
+       cts_stmt_finalize(stmt);
+
+       *retgroup = (CTSvalue *)group;
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_update_group(CTSvalue *group)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MIN_LEN] = {0};
+       cts_group *record = (cts_group *)group;
+
+       retv_if(NULL == group, CTS_ERR_ARG_NULL);
+       retvm_if(CTS_VALUE_GROUP != group->v_type, CTS_ERR_ARG_INVALID,
+                       "group is invalid type(%d)", group->v_type);
+       retvm_if(NULL == record->name, CTS_ERR_ARG_INVALID,
+                       "The name of group is empty.");
+
+       snprintf(query, sizeof(query), "UPDATE %s SET group_name=?, ringtone=? "
+                       "WHERE group_id=%d", CTS_TABLE_GROUPS, record->id);
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       stmt = cts_query_prepare(query);
+       if (NULL == stmt) {
+               ERR("cts_query_prepare() Failed");
+               contacts_svc_end_trans(false);
+               return CTS_ERR_DB_FAILED;
+       }
+
+       cts_stmt_bind_text(stmt, 1, record->name);
+       if (record->ringtone_path)
+               cts_stmt_bind_text(stmt, 2, record->ringtone_path);
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       cts_stmt_finalize(stmt);
+
+       cts_set_group_noti();
+
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_insert_group(int addressbook_id, CTSvalue *group)
+{
+       int ret, index;
+       cts_stmt stmt = NULL;
+       cts_group *record = (cts_group *)group;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       retv_if(NULL == group, CTS_ERR_ARG_NULL);
+       retvm_if(CTS_VALUE_GROUP != group->v_type, CTS_ERR_ARG_INVALID,
+                       "group is invalid type(%d)", group->v_type);
+       retvm_if(NULL == record->name, CTS_ERR_ARG_INVALID,
+                       "The name of group is empty.");
+
+       snprintf(query, sizeof(query),
+                       "INSERT INTO %s(addrbook_id, group_name, ringtone) "
+                       "VALUES(%d, ?, ?)",
+                       CTS_TABLE_GROUPS, addressbook_id);
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       stmt = cts_query_prepare(query);
+       if (NULL == stmt) {
+               ERR("cts_query_prepare() Failed");
+               contacts_svc_end_trans(false);
+               return CTS_ERR_DB_FAILED;
+       }
+
+       cts_stmt_bind_text(stmt, 1, record->name);
+
+       if (record->ringtone_path)
+               cts_stmt_bind_text(stmt, 2, record->ringtone_path);
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       index = cts_db_get_last_insert_id();
+       cts_stmt_finalize(stmt);
+
+       cts_set_group_noti();
+       ret = contacts_svc_end_trans(true);
+       retvm_if(ret < CTS_SUCCESS, ret,
+                       "contacts_svc_end_trans(true) Failed(%d)", ret);
+
+       return index;
+}
+
+API int contacts_svc_delete_group_with_members(int index)
+{
+       int ret;
+       char  query[CTS_SQL_MAX_LEN] = {0};
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       snprintf(query, sizeof(query), "DELETE FROM %s WHERE contact_id "
+                       "IN (SELECT contact_id FROM %s A WHERE group_id = %d AND "
+                       "(SELECT COUNT(*) FROM %s B WHERE A.contact_id = B.contact_id) = 1)",
+                       CTS_TABLE_CONTACTS, CTS_TABLE_GROUPING_INFO, index, CTS_TABLE_GROUPING_INFO);
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       snprintf(query, sizeof(query), "DELETE FROM %s WHERE group_id = %d",
+                       CTS_TABLE_GROUPS, index);
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       ret = cts_db_change();
+       if (0 < ret) {
+               cts_set_contact_noti();
+               cts_set_group_noti();
+               ret = contacts_svc_end_trans(true);
+       } else {
+               contacts_svc_end_trans(false);
+               ret = CTS_ERR_NO_DATA;
+       }
+
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_delete_group(int index)
+{
+       int ret;
+       char  query[CTS_SQL_MAX_LEN] = {0};
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       snprintf(query, sizeof(query), "DELETE FROM %s WHERE group_id=%d",
+                       CTS_TABLE_GROUPS, index);
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       ret = cts_db_change();
+       if (0 < ret) {
+               cts_set_group_noti();
+               ret = contacts_svc_end_trans(true);
+       } else {
+               contacts_svc_end_trans(false);
+               ret = CTS_ERR_NO_DATA;
+       }
+
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+int cts_group_set_relation(int group_id, int contact_id, int contact_acc)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MIN_LEN];
+
+#ifdef CTS_CHECK_SAME_ADDRESSBOOK
+       snprintf(query, sizeof(query),
+                       "SELECT addrbook_id FROM %s WHERE group_id = %d",
+                       CTS_TABLE_GROUPS, group_id);
+       int grp_acc = cts_query_get_first_int_result(query);
+       retvm_if(CTS_ERR_DB_RECORD_NOT_FOUND == grp_acc, CTS_ERR_ARG_INVALID,
+                       "group_id(%d) is Invalid", group_id);
+
+       retvm_if(contact_acc != grp_acc, CTS_ERR_ARG_INVALID,
+                       "addrbook_id(%d) of the contact and addrbook_id(%d) of the group is not same",
+                       contact_acc, grp_acc);
+#endif
+       snprintf(query, sizeof(query), "INSERT OR IGNORE INTO %s VALUES(%d, %d)",
+                       CTS_TABLE_GROUPING_INFO, group_id, contact_id);
+
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       warn_if(CTS_SUCCESS != ret, "cts_stmt_step() Failed(%d)", ret);
+
+       cts_stmt_finalize(stmt);
+
+       return ret;
+}
+
+API int contacts_svc_group_set_relation(int group_id, int contact_id)
+{
+       int ret, ct_acc=0;
+
+#ifndef CTS_CHECK_SAME_ADDRESSBOOK
+       retvm_if(!group_id, CTS_ERR_ARG_INVALID, "group_id is 0");
+       retvm_if(!contact_id, CTS_ERR_ARG_INVALID, "contact_id is 0");
+#else
+       char query[CTS_SQL_MIN_LEN];
+
+       snprintf(query, sizeof(query),
+                       "SELECT addrbook_id FROM %s WHERE contact_id = %d",
+                       CTS_TABLE_CONTACTS, contact_id);
+       ct_acc = cts_query_get_first_int_result(query);
+       retvm_if(CTS_ERR_DB_RECORD_NOT_FOUND == ct_acc, CTS_ERR_ARG_INVALID,
+                       "contact_id(%d) is Invalid", contact_id);
+#endif
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       ret = cts_group_set_relation(group_id, contact_id, ct_acc);
+       if (ret) {
+               contacts_svc_end_trans(false);
+               ERR("cts_group_set_relation() Failed(%d)", ret);
+               return ret;
+       }
+
+       ret = cts_update_contact_changed_time(contact_id);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_update_contact_changed_time() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       cts_set_contact_noti();
+       cts_set_group_rel_noti();
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+int cts_group_unset_relation(int group_id, int contact_id)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MIN_LEN];
+
+       snprintf(query, sizeof(query),
+                       "DELETE FROM %s WHERE group_id = %d AND contact_id = %d",
+                       CTS_TABLE_GROUPING_INFO, group_id, contact_id);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       warn_if(CTS_SUCCESS != ret, "cts_stmt_step() Failed(%d)", ret);
+
+       cts_stmt_finalize(stmt);
+
+       return ret;
+}
+
+API int contacts_svc_group_unset_relation(int group_id, int contact_id)
+{
+       int ret;
+
+       retvm_if(!group_id, CTS_ERR_ARG_INVALID, "group_id is 0");
+       retvm_if(!contact_id, CTS_ERR_ARG_INVALID, "contact_id is 0");
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       ret = cts_group_unset_relation(group_id, contact_id);
+       if (ret) {
+               contacts_svc_end_trans(false);
+               ERR("cts_group_unset_relation() Failed(%d)", ret);
+               return ret;
+       }
+
+       ret = cts_update_contact_changed_time(contact_id);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_update_contact_changed_time() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       cts_set_contact_noti();
+       cts_set_group_rel_noti();
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
diff --git a/src/cts-group.h b/src/cts-group.h
new file mode 100755 (executable)
index 0000000..472b68f
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_GROUP_H__
+#define __CTS_GROUP_H__
+
+int cts_group_set_relation(int group_id, int contact_id, int contact_acc);
+int cts_group_unset_relation(int group_id, int contact_id);
+
+/**
+ * This function gets index of group found by name.
+ * @param[in] addressbook_id The index of addressbook. 0 is local(phone internal)
+ * @param[in] name The group name for searching
+ * @return index of found group on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void get_group(void)
+ {
+    int index, ret=-1;
+    CTSvalue *group = NULL;
+
+    index = contacts_svc_find_group(0, "Family");
+    if(index > CTS_SUCCESS)
+       ret = contacts_svc_get_group(index, &group);
+    if(ret < CTS_SUCCESS) {
+         printf("contacts_svc_get_group() Failed");
+         return;
+    }
+ }
+ * @endcode
+ */
+int contacts_svc_find_group(int addressbook_id, const char *name);
+
+
+//<!--
+/**
+ * @defgroup   CONTACTS_SVC_GROUP Group information
+ * @ingroup    CONTACTS_SVC
+ * @addtogroup CONTACTS_SVC_GROUP
+ * @{
+ *
+ * This interface provides methods for group information.
+ *
+ */
+
+/**
+ * This function sets the relationship between a group and a contact.
+ * It is low level api. It is recommanded to use contacts_svc_update_contact()
+ * \n The contact and the group must have the same addressbook index.
+ * (It is not checked internally for performance.)
+ *
+ * @param[in] group_id Index of group record
+ * @param[in] contact_id Index of contact record to add to group
+ * @return the index of group on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+
+ * @endcode
+ */
+int contacts_svc_group_set_relation(int group_id, int contact_id);
+
+/**
+ * This function removes relation between a group and a contact.
+ * It is low level api. It is recommanded to use contacts_svc_update_contact()
+ *
+ * @param[in] group_id Index of group record
+ * @param[in] contact_id Index of contact record to add to group
+ * @return the index of group on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+
+ * @endcode
+ */
+int contacts_svc_group_unset_relation(int group_id, int contact_id);
+
+/**
+ * This function inserts a group into database.
+ * This api assigns a index of the group automatically.
+ * \n The returned index is unique & non-reusable.
+ *
+ * @param[in] addressbook_id The index of addressbook. 0 is local(phone internal)
+ * @param[in] group A group information of CTSvalue() created by contacts_svc_value_new(CTS_VALUE_GROUP).
+ * @return the index of group on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void insert_group(const char *group_name)
+ {
+    int ret;
+    CTSvalue *group;
+    group = contacts_svc_value_new(CTS_VALUE_GROUP);
+
+    contacts_svc_value_set_str(group, CTS_GROUP_VAL_NAME_STR, group_name);
+    contacts_svc_value_set_str(group, CTS_GROUP_VAL_RINGTONE_STR,"/tmp/test.mp3");
+
+    ret = contacts_svc_insert_group(0, group);
+    if(ret < CTS_SUCCESS)
+       printf("contacts_svc_insert_group() Failed\n");
+
+    contacts_svc_value_free(group);
+ }
+ * @endcode
+ */
+int contacts_svc_insert_group(int addressbook_id, CTSvalue *group);
+
+/**
+ * This function updates a group in the database.
+ *
+ * @param[in] group A group information of #CTSvalue.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void update_group(void)
+ {
+    int ret;
+    CTSvalue *group = NULL;
+    ret = contacts_svc_get_group(2, &group);
+    if(CTS_SUCCESS != ret) {
+         printf("contacts_svc_get_group() Failed");
+         return;
+    }
+
+    contacts_svc_value_set_str(group, CTS_GROUP_VAL_NAME_STR,"Fix-Friends");
+    contacts_svc_value_set_str(group, CTS_GROUP_VAL_RINGTONE_STR,"/tmp/change.mp3");
+
+    //free("Fix-Friends");
+    //free("/tmp/change.mp3");
+    ret = contacts_svc_update_group(group);
+    if(ret < CTS_SUCCESS)
+       printf("contacts_svc_update_group() Failed\n");
+
+    contacts_svc_value_free(group);
+ }
+ * @endcode
+ */
+int contacts_svc_update_group(CTSvalue *group);
+
+/**
+ * This function deletes a group in database.
+ *
+ * @param[in] index The index of group to delete in database.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void delete_group(void)
+ {
+    int ret;
+    ret = contacts_svc_delete_group(3);
+    if(CTS_SUCCESS != ret)
+       printf("Error : contacts_svc_delete_group() Failed(%d)", ret);
+ }
+ * @endcode
+ */
+int contacts_svc_delete_group(int index);
+
+/**
+ * This function deletes contacts inclued the group and the group in database.
+ * But if the contact has another group, it deletes the group relations only.
+ *
+ * @param[in] index The index of group to delete in database.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void delete_group_members(void)
+ {
+    int ret;
+    ret = contacts_svc_delete_group_with_members(3);
+    if(CTS_SUCCESS != ret)
+       printf("Error : contacts_svc_delete_group_with_members() Failed(%d)", ret);
+ }
+ * @endcode
+ */
+int contacts_svc_delete_group_with_members(int index);
+
+/**
+ * This function gets a group record which has the index from the database.
+ * Obtained group record should be free using by contacts_svc_value_free().
+ * @param[in] index The index of group to get
+ * @param[out] retgroup Points of the group record which is returned
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void get_group(void)
+ {
+    int ret;
+    CTSvalue *group = NULL;
+    ret = contacts_svc_get_group(2, &group);
+    if(CTS_SUCCESS != ret) {
+         printf("contacts_svc_get_list() Failed");
+         return;
+    }
+
+    printf("Account ID : %d\n",
+             contacts_svc_value_get_int(group, CTS_GROUP_VAL_ADDRESSBOOK_ID_INT));
+    printf("Name : %s\n",
+       contacts_svc_value_get_str(group, CTS_GROUP_VAL_NAME_STR));
+    if(contacts_svc_value_get_str(group, CTS_GROUP_VAL_RINGTONE_STR))
+       printf("ringtone : %s\n",
+          contacts_svc_value_get_str(group, CTS_GROUP_VAL_RINGTONE_STR));
+ }
+ * @endcode
+ */
+int contacts_svc_get_group(int index, CTSvalue **retgroup);
+
+/**
+ * @}
+ */
+//-->
+#endif //__CTS_GROUP_H__
+
diff --git a/src/cts-inotify.c b/src/cts-inotify.c
new file mode 100755 (executable)
index 0000000..553fe3c
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/inotify.h>
+
+#include "cts-internal.h"
+
+typedef struct
+{
+       int wd;
+       void (*cb)(void *);
+       void *cb_data;
+}noti_info;
+
+static int cts_inoti_fd = -1;
+static guint cts_inoti_handler;
+static GSList *cts_noti_list;
+
+static inline void handle_callback(GSList *noti_list, int wd, uint32_t mask)
+{
+       noti_info *noti;
+       GSList *it = NULL;
+
+       for (it = noti_list;it;it=it->next)
+       {
+               noti = (noti_info *)it->data;
+               if (noti->wd == wd) {
+                       if ((mask & IN_CLOSE_WRITE) && noti->cb)
+                               noti->cb(noti->cb_data);
+               }
+       }
+}
+
+static gboolean cts_inotify_gio_cb(GIOChannel *src, GIOCondition cond, gpointer data)
+{
+       int fd, ret;
+       struct inotify_event ie;
+       char name[FILENAME_MAX];
+
+       fd = g_io_channel_unix_get_fd(src);
+
+       while (0 < (ret = read(fd, &ie, sizeof(ie)))) {
+               if (sizeof(ie) == ret) {
+                       if (cts_noti_list)
+                               handle_callback(cts_noti_list, ie.wd, ie.mask);
+
+                       while (0 < ie.len) {
+                               ret = read(fd, name, (ie.len<sizeof(name))?ie.len:sizeof(name));
+                               if (-1 == ret) {
+                                       if (EINTR == errno)
+                                               continue;
+                                       else
+                                               break;
+                               }
+                               ie.len -= ret;
+                       }
+               }else {
+                       while (ret < sizeof(ie)) {
+                               int read_size;
+                               read_size = read(fd, name, sizeof(ie)-ret);
+                               if (-1 == read_size) {
+                                       if (EINTR == errno)
+                                               continue;
+                                       else
+                                               break;
+                               }
+                               ret += read_size;
+                       }
+               }
+       }
+
+       return TRUE;
+}
+
+static inline int cts_inotify_attach_handler(int fd)
+{
+       guint ret;
+       GIOChannel *channel;
+
+       retvm_if(fd < 0, CTS_ERR_ARG_INVALID, "fd is invalid");
+
+       channel = g_io_channel_unix_new(fd);
+       retvm_if(NULL == channel, CTS_ERR_INOTIFY_FAILED, "g_io_channel_unix_new() Failed");
+
+       g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL);
+
+       ret = g_io_add_watch(channel, G_IO_IN, cts_inotify_gio_cb, NULL);
+       g_io_channel_unref(channel);
+
+       return ret;
+}
+
+int cts_inotify_init(void)
+{
+       cts_inoti_fd = inotify_init();
+       retvm_if(-1 == cts_inoti_fd, CTS_ERR_INOTIFY_FAILED,
+                       "inotify_init() Failed(%d)", errno);
+
+       fcntl(cts_inoti_fd, F_SETFD, FD_CLOEXEC);
+       fcntl(cts_inoti_fd, F_SETFL, O_NONBLOCK);
+
+       cts_inoti_handler = cts_inotify_attach_handler(cts_inoti_fd);
+       if (cts_inoti_handler <= 0) {
+               ERR("cts_inotify_attach_handler() Failed");
+               close(cts_inoti_fd);
+               cts_inoti_fd = -1;
+               cts_inoti_handler = 0;
+               return CTS_ERR_INOTIFY_FAILED;
+       }
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_inotify_get_wd(int fd, const char *notipath)
+{
+       return inotify_add_watch(fd, notipath, IN_ACCESS);
+}
+
+static inline int cts_inotify_watch(int fd, const char *notipath)
+{
+       int ret;
+
+       ret = inotify_add_watch(fd, notipath, IN_CLOSE_WRITE);
+       retvm_if(-1 == ret, CTS_ERR_INOTIFY_FAILED,
+                       "inotify_add_watch() Failed(%d)", errno);
+
+       return CTS_SUCCESS;
+}
+
+int cts_inotify_subscribe(const char *path, void (*cb)(void *), void *data)
+{
+       int ret, wd;
+       noti_info *noti, *same_noti = NULL;
+       GSList *it;
+
+       retv_if(NULL==path, CTS_ERR_ARG_NULL);
+       retv_if(NULL==cb, CTS_ERR_ARG_NULL);
+       retvm_if(cts_inoti_fd < 0, CTS_ERR_ENV_INVALID,
+                       "cts_inoti_fd(%d) is invalid", cts_inoti_fd);
+
+       wd = cts_inotify_get_wd(cts_inoti_fd, path);
+       retvm_if(-1 == wd, CTS_ERR_INOTIFY_FAILED,
+                       "cts_inotify_get_wd() Failed(%d)", errno);
+
+       for (it=cts_noti_list;it;it=it->next)
+       {
+               if (it->data)
+               {
+                       same_noti = it->data;
+                       if (same_noti->wd == wd && same_noti->cb == cb && same_noti->cb_data == data) {
+                               break;
+                       }
+                       else {
+                               same_noti = NULL;
+                       }
+               }
+       }
+
+       if (same_noti) {
+               cts_inotify_watch(cts_inoti_fd, path);
+               ERR("The same callback(%s) is already exist", path);
+               return CTS_ERR_ALREADY_EXIST;
+       }
+
+       ret = cts_inotify_watch(cts_inoti_fd, path);
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_inotify_watch() Failed");
+
+       noti = calloc(1, sizeof(noti_info));
+       retvm_if(NULL == noti, CTS_ERR_OUT_OF_MEMORY, "calloc() Failed");
+
+       noti->wd = wd;
+       noti->cb_data = data;
+       noti->cb = cb;
+       cts_noti_list = g_slist_append(cts_noti_list, noti);
+
+       return CTS_SUCCESS;
+}
+
+static inline int del_noti_with_data(GSList **noti_list, int wd,
+               void (*cb)(void *), void *user_data)
+{
+       int del_cnt, remain_cnt;
+       GSList *it, *result;
+
+       del_cnt = 0;
+       remain_cnt = 0;
+
+       it = result = *noti_list;
+       while (it)
+       {
+               noti_info *noti = it->data;
+               if (noti && wd == noti->wd)
+               {
+                       if (cb == noti->cb && user_data == noti->cb_data) {
+                               it = it->next;
+                               result = g_slist_remove(result , noti);
+                               free(noti);
+                               del_cnt++;
+                               continue;
+                       }
+                       else {
+                               remain_cnt++;
+                       }
+               }
+               it = it->next;
+       }
+       retvm_if(del_cnt == 0, CTS_ERR_NO_DATA, "nothing deleted");
+
+       *noti_list = result;
+
+       return remain_cnt;
+}
+
+static inline int del_noti(GSList **noti_list, int wd, void (*cb)(void *))
+{
+       int del_cnt, remain_cnt;
+       GSList *it, *result;
+
+       del_cnt = 0;
+       remain_cnt = 0;
+
+       it = result = *noti_list;
+       while (it)
+       {
+               noti_info *noti = it->data;
+               if (noti && wd == noti->wd)
+               {
+                       if (NULL == cb || noti->cb == cb) {
+                               it = it->next;
+                               result = g_slist_remove(result, noti);
+                               free(noti);
+                               del_cnt++;
+                               continue;
+                       }
+                       else {
+                               remain_cnt++;
+                       }
+               }
+               it = it->next;
+       }
+       retvm_if(del_cnt == 0, CTS_ERR_NO_DATA, "nothing deleted");
+
+       *noti_list = result;
+
+       return remain_cnt;
+}
+
+int cts_inotify_unsubscribe(const char *path, void (*cb)(void *))
+{
+       int ret, wd;
+
+       retv_if(NULL == path, CTS_ERR_ARG_NULL);
+       retvm_if(cts_inoti_fd < 0, CTS_ERR_ENV_INVALID,
+                       "cts_inoti_fd(%d) is invalid", cts_inoti_fd);
+
+       wd = cts_inotify_get_wd(cts_inoti_fd, path);
+       retvm_if(-1 == wd, CTS_ERR_INOTIFY_FAILED,
+                       "cts_inotify_get_wd() Failed(%d)", errno);
+
+       ret = del_noti(&cts_noti_list, wd, cb);
+       warn_if(ret < CTS_SUCCESS, "del_noti() Failed(%d)", ret);
+
+       if (0 == ret)
+               return inotify_rm_watch(cts_inoti_fd, wd);
+
+       return cts_inotify_watch(cts_inoti_fd, path);
+}
+
+int cts_inotify_unsubscribe_with_data(const char *path,
+               void (*cb)(void *), void *user_data)
+{
+       int ret, wd;
+
+       retv_if(NULL==path, CTS_ERR_ARG_NULL);
+       retv_if(NULL==cb, CTS_ERR_ARG_NULL);
+       retvm_if(cts_inoti_fd < 0, CTS_ERR_ENV_INVALID,
+                       "cts_inoti_fd(%d) is invalid", cts_inoti_fd);
+
+       wd = cts_inotify_get_wd(cts_inoti_fd, path);
+       retvm_if(-1 == wd, CTS_ERR_INOTIFY_FAILED,
+                       "cts_inotify_get_wd() Failed(%d)", errno);
+
+       ret = del_noti_with_data(&cts_noti_list, wd, cb, user_data);
+       warn_if(ret < CTS_SUCCESS, "del_noti_with_data() Failed(%d)", ret);
+
+       if (0 == ret)
+               return inotify_rm_watch(cts_inoti_fd, wd);
+
+       return cts_inotify_watch(cts_inoti_fd, path);
+}
+
+static void clear_nslot_list(gpointer data, gpointer user_data)
+{
+       free(data);
+}
+
+static inline gboolean cts_inotify_detach_handler(guint id)
+{
+       return g_source_remove(id);
+}
+
+void cts_inotify_close(void)
+{
+       if (cts_inoti_handler) {
+               cts_inotify_detach_handler(cts_inoti_handler);
+               cts_inoti_handler = 0;
+       }
+
+       if (cts_noti_list) {
+               g_slist_foreach(cts_noti_list, clear_nslot_list, NULL);
+               g_slist_free(cts_noti_list);
+               cts_noti_list = NULL;
+       }
+
+       if (0 <= cts_inoti_fd) {
+               close(cts_inoti_fd);
+               cts_inoti_fd = -1;
+       }
+}
diff --git a/src/cts-inotify.h b/src/cts-inotify.h
new file mode 100755 (executable)
index 0000000..5d092f7
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_INOTIFY_H__
+#define __CTS_INOTIFY_H__
+
+int cts_inotify_init(void);
+void cts_inotify_close(void);
+int cts_inotify_subscribe(const char *path, void (*cb)(void *), void *data);
+int cts_inotify_unsubscribe(const char *path, void (*cb)(void *));
+int cts_inotify_unsubscribe_with_data(const char *path,
+               void (*cb)(void *), void *user_data);
+
+
+#endif //__CTS_INOTIFY_H__
diff --git a/src/cts-internal.h b/src/cts-internal.h
new file mode 100755 (executable)
index 0000000..66cc489
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_INTERNAL_H__
+#define __CTS_INTERNAL_H__
+
+#include <stdio.h>
+#include "cts-errors.h"
+#include "cts-struct.h"
+
+#ifndef API
+#define API __attribute__ ((visibility("default")))
+#endif
+
+#define SAFE_STR(src) (src)?src:""
+
+#define CTS_DLOG_OUT
+//#define CTS_DEBUGGING
+//#define CTS_TIMECHECK
+
+#ifdef CTS_DLOG_OUT
+#define LOG_TAG "CONTACTS_SVC"
+#include <dlog.h>
+#define DLOG(prio, fmt, arg...) \
+       do { SLOG(prio, LOG_TAG, fmt, ##arg); } while (0)
+#define INFO(fmt, arg...) SLOGI(fmt, ##arg)
+#define ERR(fmt, arg...) SLOGE("%s(%d): " fmt, __FUNCTION__, __LINE__, ##arg)
+#define DBG(fmt, arg...) SLOGD("%s:" fmt, __FUNCTION__, ##arg)
+#else
+#include <unistd.h>
+#define PRT(prio, fmt, arg...) \
+       do { fprintf((prio?stderr:stdout),"[Contacts-service]" fmt"\n", ##arg); } while (0)
+#define INFO(fmt, arg...) PRT(0, fmt, ##arg)
+#define ERR(fmt, arg...) PRT(1,"%s(%d): " fmt, __FUNCTION__, __LINE__, ##arg)
+#define DBG(fmt, arg...) \
+       do { \
+               printf("\x1b[105;37m[%d]\x1b[0m(%s)" fmt "\n", getpid(), __FUNCTION__, ##arg); \
+       } while (0)
+#endif
+
+#ifdef CTS_DEBUGGING
+#define CTS_FN_CALL DBG(">>>>>>>> called")
+#define CTS_FN_END DBG("<<<<<<<< ended")
+#define CTS_DBG(fmt, arg...) DBG("(%d) " fmt, __LINE__, ##arg)
+#else /* CTS_DEBUGGING */
+#define CTS_FN_CALL
+#define CTS_FN_END
+#define CTS_DBG(fmt, arg...)
+#endif /* CTS_DEBUGGING */
+
+#define warn_if(expr, fmt, arg...) do { \
+       if (expr) { \
+               ERR(fmt, ##arg); \
+       } \
+} while (0)
+#define ret_if(expr) do { \
+       if (expr) { \
+               ERR("(%s)", #expr); \
+               return; \
+       } \
+} while (0)
+#define retv_if(expr, val) do { \
+       if (expr) { \
+               ERR("(%s)", #expr); \
+               return (val); \
+       } \
+} while (0)
+#define retm_if(expr, fmt, arg...) do { \
+       if (expr) { \
+               ERR(fmt, ##arg); \
+               return; \
+       } \
+} while (0)
+#define retvm_if(expr, val, fmt, arg...) do { \
+       if (expr) { \
+               ERR(fmt, ##arg); \
+               return (val); \
+       } \
+} while (0)
+
+/************** TimeCheck ***************/
+#ifdef CTS_TIMECHECK
+
+double correction, startT;
+double cts_set_start_time(void);
+double cts_exec_time(double start);
+int cts_init_time(void);
+#define CTS_START_TIME_CHECK \
+       cts_init_time();\
+startT = cts_set_start_time()
+#define CTS_END_TIME_CHECK(fmt, arg...) \
+       DBG(fmt" time = %f ms\n", ##arg, cts_exec_time(startT))
+
+#else /* CTS_TIMECHECK */
+
+#define CTS_START_TIME_CHECK
+#define CTS_END_TIME_CHECK(arg)
+
+#endif /* CTS_TIMECHECK */
+
+#endif /* __CTS_INTERNAL_H__ */
+
diff --git a/src/cts-list-info.c b/src/cts-list-info.c
new file mode 100755 (executable)
index 0000000..96e23b9
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "cts-internal.h"
+#include "cts-normalize.h"
+#include "cts-utils.h"
+#include "cts-list.h"
+
+static inline CTSvalue* cts_iter_get_info_contact(cts_stmt stmt, int type)
+{
+       int i, lang;
+       char *temp;
+       contact_list *result;
+
+       result = (contact_list *)contacts_svc_value_new(CTS_VALUE_LIST_CONTACT);
+       retvm_if(NULL == result, NULL, "contacts_svc_value_new() Failed");
+
+       i = 0;
+       result->id = cts_stmt_get_int(stmt, i++);
+       lang = cts_stmt_get_int(stmt, i++);
+       temp = cts_stmt_get_text(stmt, i++);
+       result->first = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, i++);
+       result->last = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, i++);
+       result->display = SAFE_STRDUP(temp);
+       result->acc_id = cts_stmt_get_int(stmt, i++);
+       temp = cts_stmt_get_text(stmt, i++);
+       result->img_path = SAFE_STRDUP(temp);
+
+       if (CTS_LANG_DEFAULT == lang)
+               lang = cts_get_default_language();
+
+       if (NULL == result->display && result->first && result->last
+                       && CTS_LANG_ENGLISH == lang) {
+               char display[CTS_SQL_MAX_LEN];
+               if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       snprintf(display, sizeof(display), "%s %s", result->first, result->last);
+               else
+                       snprintf(display, sizeof(display), "%s, %s", result->last, result->first);
+
+               result->display = strdup(display);
+       }
+       if (CTS_ITER_CONTACTS_WITH_NAME != type) {
+               temp = cts_stmt_get_text(stmt, i++);
+               result->normalize = SAFE_STRDUP(temp);
+       }
+
+       return (CTSvalue *)result;
+}
+
+static inline CTSvalue* cts_iter_get_info_number_email(cts_stmt stmt, int type)
+{
+       int i, lang;
+       char *temp;
+       contact_list *result;
+
+       result = (contact_list *)contacts_svc_value_new(CTS_VALUE_LIST_CONTACT);
+       retvm_if(NULL == result, NULL, "contacts_svc_value_new() Failed");
+       if (CTS_ITER_EMAILINFOS_WITH_EMAIL == type)
+               result->v_type = CTS_VALUE_LIST_EMAILINFO;
+       else if (CTS_ITER_NUMBERS_EMAILS == type)
+               result->v_type = CTS_VALUE_LIST_NUMS_EMAILS;
+       else
+               result->v_type = CTS_VALUE_LIST_NUMBERINFO;
+
+       i = 0;
+       result->id = cts_stmt_get_int(stmt, i++);
+       lang = cts_stmt_get_int(stmt, i++);
+       temp = cts_stmt_get_text(stmt, i++);
+       result->first = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, i++);
+       result->last = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, i++);
+       result->display = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, i++);
+       result->connect = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, i++);
+       result->img_path = SAFE_STRDUP(temp);
+       if (CTS_ITER_NUMBERS_EMAILS == type) {
+               result->acc_id = cts_stmt_get_int(stmt, i++);
+               temp = cts_stmt_get_text(stmt, i++);
+               result->normalize = SAFE_STRDUP(temp);
+       }
+
+       if (CTS_LANG_DEFAULT == lang)
+               lang = cts_get_default_language();
+
+       if (NULL == result->display && result->first && result->last
+                       && CTS_LANG_ENGLISH == lang) {
+               char display[CTS_SQL_MAX_LEN];
+               if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       snprintf(display, sizeof(display), "%s %s", result->first, result->last);
+               else
+                       snprintf(display, sizeof(display), "%s, %s", result->last, result->first);
+
+               result->display = strdup(display);
+       }
+
+       return (CTSvalue *)result;
+}
+
+static inline CTSvalue* cts_iter_get_info_sdn(cts_stmt stmt, int type)
+{
+       char *temp;
+       sdn_list *result;
+
+       result = (sdn_list *)contacts_svc_value_new(CTS_VALUE_LIST_SDN);
+       retvm_if(NULL == result, NULL, "contacts_svc_value_new() Failed");
+
+       temp = cts_stmt_get_text(stmt, 0);
+       result->name = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, 1);
+       result->number = SAFE_STRDUP(temp);
+
+       return (CTSvalue *)result;
+}
+
+static inline CTSvalue* cts_iter_get_info_change(updated_contact *cursor)
+{
+       change_list *result;
+
+       result = (change_list *)contacts_svc_value_new(CTS_VALUE_LIST_CHANGE);
+       retvm_if(NULL == result, NULL, "contacts_svc_value_new() Failed");
+
+       result->changed_type = cursor->type;
+       result->id = cursor->id;
+       result->changed_ver = cursor->ver;
+
+       return (CTSvalue *)result;
+}
+
+static inline CTSvalue* cts_iter_get_info_plog(int type, cts_stmt stmt)
+{
+       int lang, cnt=0;
+       char *temp;
+       plog_list *result;
+
+       result = (plog_list *)contacts_svc_value_new(CTS_VALUE_LIST_PLOG);
+       retvm_if(NULL == result, NULL, "contacts_svc_value_new() Failed");
+
+       switch (type)
+       {
+       case CTS_ITER_GROUPING_PLOG:
+               result->id = cts_stmt_get_int(stmt, cnt++);
+               lang = cts_stmt_get_int(stmt, cnt++);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->first = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->last = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->display = SAFE_STRDUP(temp);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->img_path = SAFE_STRDUP(temp);
+               if (CTS_LANG_DEFAULT == lang)
+                       lang = cts_get_default_language();
+
+               if (NULL == result->display && result->first && result->last
+                               && CTS_LANG_ENGLISH == lang) {
+                       char display[CTS_SQL_MAX_LEN];
+                       if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                               snprintf(display, sizeof(display), "%s %s", result->first, result->last);
+                       else
+                               snprintf(display, sizeof(display), "%s, %s", result->last, result->first);
+
+                       result->display = strdup(display);
+               }
+
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->number = SAFE_STRDUP(temp);
+               result->log_type = cts_stmt_get_int(stmt, cnt++);
+               result->log_time = cts_stmt_get_int(stmt, cnt++);
+               result->extra_data1 = cts_stmt_get_int(stmt, cnt++);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->extra_data2 = SAFE_STRDUP(temp);
+               result->related_id = cts_stmt_get_int(stmt, cnt++);
+               result->num_type = cts_stmt_get_int(stmt, cnt++);
+               break;
+       case CTS_ITER_PLOGS_OF_NUMBER:
+               result->id = cts_stmt_get_int(stmt, cnt++);
+               result->log_type = cts_stmt_get_int(stmt, cnt++);
+               result->log_time = cts_stmt_get_int(stmt, cnt++);
+               result->extra_data1 = cts_stmt_get_int(stmt, cnt++);
+               temp = cts_stmt_get_text(stmt, cnt++);
+               result->extra_data2 = SAFE_STRDUP(temp);
+               result->related_id = cts_stmt_get_int(stmt, cnt++);
+               break;
+       default:
+               ERR("Invalid parameter : The type(%d) is unknown type", type);
+               contacts_svc_value_free((CTSvalue*)result);
+               return NULL;
+       }
+       return (CTSvalue *)result;
+}
+
+static inline CTSvalue* cts_iter_get_info_custom_num_type(cts_stmt stmt)
+{
+       numtype_list *result;
+
+       result = (numtype_list *)contacts_svc_value_new(CTS_VALUE_LIST_CUSTOM_NUM_TYPE);
+       retvm_if(NULL == result, NULL, "contacts_svc_value_new() Failed");
+
+       result->id = cts_stmt_get_int(stmt, 0);
+       result->name = SAFE_STRDUP(cts_stmt_get_text(stmt, 1));
+
+       return (CTSvalue *)result;
+}
+
+static inline CTSvalue* cts_iter_get_info_addrbook(cts_stmt stmt)
+{
+       cts_addrbook *result;
+
+       result = (cts_addrbook *)contacts_svc_value_new(CTS_VALUE_LIST_ADDRBOOK);
+       retvm_if(NULL == result, NULL, "contacts_svc_value_new() Failed");
+
+       cts_stmt_get_addressbook(stmt, result);
+
+       return (CTSvalue *)result;
+}
+
+static inline CTSvalue* cts_iter_get_info_group(cts_stmt stmt)
+{
+       cts_group *result;
+
+       result = (cts_group *)contacts_svc_value_new(CTS_VALUE_LIST_GROUP);
+       retvm_if(NULL == result, NULL, "contacts_svc_value_new() Failed");
+
+       result->id = cts_stmt_get_int(stmt, 0);
+       result->addrbook_id = cts_stmt_get_int(stmt, 1);
+       result->name = SAFE_STRDUP(cts_stmt_get_text(stmt, 2));
+
+       return (CTSvalue *)result;
+}
+
+static inline CTSvalue* cts_iter_get_info_shortcut(int type, cts_stmt stmt)
+{
+       int i, lang;
+       char *temp;
+       shortcut_list *result;
+
+       result = (shortcut_list *)contacts_svc_value_new(CTS_VALUE_LIST_SHORTCUT);
+       retvm_if(NULL == result, NULL, "contacts_svc_value_new() Failed");
+
+       i = 0;
+       result->contact_id = cts_stmt_get_int(stmt, i++);
+       lang = cts_stmt_get_int(stmt, i++);
+       temp = cts_stmt_get_text(stmt, i++);
+       result->first = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, i++);
+       result->last = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, i++);
+       result->display = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, i++);
+       result->img_path = SAFE_STRDUP(temp);
+       result->id = cts_stmt_get_int(stmt, i++);
+       if (CTS_LANG_DEFAULT == lang)
+               lang = cts_get_default_language();
+
+       if (NULL == result->display && result->first && result->last
+                       && CTS_LANG_ENGLISH == lang) {
+               char display[CTS_SQL_MAX_LEN];
+               if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       snprintf(display, sizeof(display), "%s %s", result->first, result->last);
+               else
+                       snprintf(display, sizeof(display), "%s, %s", result->last, result->first);
+
+               result->display = strdup(display);
+       }
+
+       if (CTS_ITER_ALL_CONTACT_FAVORITE != type) {
+               result->num_type = cts_stmt_get_int(stmt, i++);
+               temp = cts_stmt_get_text(stmt, i++);
+               result->number = SAFE_STRDUP(temp);
+
+               if (CTS_ITER_ALL_SPEEDDIAL == type)
+                       result->speeddial = cts_stmt_get_int(stmt, i++);
+       }
+
+       return (CTSvalue *)result;
+}
+
+API CTSvalue* contacts_svc_iter_get_info(CTSiter *iter)
+{
+       CTSvalue *result;
+
+       retvm_if(NULL == iter, NULL, "iter is NULL");
+
+       switch (iter->i_type)
+       {
+       case CTS_ITER_CONTACTS:
+       case CTS_ITER_CONTACTS_WITH_NAME:
+               result = cts_iter_get_info_contact(iter->stmt, iter->i_type);
+               retvm_if(NULL == result, NULL, "cts_iter_get_info_contact() Failed");
+               break;
+       case CTS_ITER_NUMBERINFOS:
+       case CTS_ITER_EMAILINFOS_WITH_EMAIL:
+       case CTS_ITER_NUMBERS_EMAILS:
+               result = cts_iter_get_info_number_email(iter->stmt, iter->i_type);
+               retvm_if(NULL == result, NULL, "cts_iter_get_info_number() Failed");
+               break;
+       case CTS_ITER_ALL_SDN:
+               result = cts_iter_get_info_sdn(iter->stmt, iter->i_type);
+               retvm_if(NULL == result, NULL, "cts_iter_get_info_number() Failed");
+               break;
+       case CTS_ITER_UPDATED_CONTACTS_AFTER_VER:
+               result = cts_iter_get_info_change(iter->info->cursor);
+               retvm_if(NULL == result, NULL, "cts_iter_get_info_change() Failed");
+               break;
+       case CTS_ITER_GROUPING_PLOG:
+       case CTS_ITER_PLOGS_OF_NUMBER:
+               result = cts_iter_get_info_plog(iter->i_type, iter->stmt);
+               retvm_if(NULL == result, NULL, "cts_iter_get_info_plog() Failed");
+               break;
+       case CTS_ITER_ALL_CUSTOM_NUM_TYPE:
+               result = cts_iter_get_info_custom_num_type(iter->stmt);
+               retvm_if(NULL == result, NULL, "cts_iter_get_info_custom_num_type() Failed");
+               break;
+       case CTS_ITER_ADDRESSBOOKS:
+               result = cts_iter_get_info_addrbook(iter->stmt);
+               retvm_if(NULL == result, NULL, "cts_iter_get_info_addrbook() Failed");
+               break;
+       case CTS_ITER_GROUPS:
+               result = cts_iter_get_info_group(iter->stmt);
+               retvm_if(NULL == result, NULL, "cts_iter_get_info_group() Failed");
+               break;
+       case CTS_ITER_ALL_NUM_FAVORITE:
+       case CTS_ITER_ALL_CONTACT_FAVORITE:
+       case CTS_ITER_ALL_SPEEDDIAL:
+               result = cts_iter_get_info_shortcut(iter->i_type, iter->stmt);
+               retvm_if(NULL == result, NULL, "cts_iter_get_info_shortcut() Failed");
+               break;
+       case CTS_ITER_PLOGNUMBERS_WITH_NUM:
+               result = (CTSvalue*)(SAFE_STRDUP(cts_stmt_get_text(iter->stmt, 0)));
+               break;
+       default:
+               ERR("Invalid parameter : The iter(%d) has unknown type", iter->i_type);
+               return NULL;
+       }
+
+       return result;
+}
+
diff --git a/src/cts-list.c b/src/cts-list.c
new file mode 100755 (executable)
index 0000000..cb289b0
--- /dev/null
@@ -0,0 +1,1447 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "cts-internal.h"
+#include "cts-schema.h"
+#include "cts-utils.h"
+#include "cts-types.h"
+#include "cts-normalize.h"
+#include "cts-favorite.h"
+#include "cts-list.h"
+
+#define CTS_MALLOC_DEFAULT_NUM 256 //4Kbytes
+#define CTS_OFTEN_USED_NUM 1
+
+static inline updated_contact* cts_updated_contact_add_mempool(void)
+{
+       int i;
+       updated_contact *mempool;
+
+       mempool = calloc(CTS_MALLOC_DEFAULT_NUM, sizeof(updated_contact));
+       for (i=0;i<CTS_MALLOC_DEFAULT_NUM-1;i++)
+               mempool[i].next = &mempool[i+1];
+       return mempool;
+}
+
+static inline int cts_updated_contact_free_mempool(updated_contact *mempool)
+{
+       updated_contact *memseg, *tmp;
+
+       retv_if(NULL == mempool, CTS_ERR_ARG_NULL);
+
+       memseg = mempool;
+       while (memseg) {
+               tmp = memseg[CTS_MALLOC_DEFAULT_NUM-1].next;
+               free(memseg);
+               memseg = tmp;
+       }
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_iter_next(CTSiter *iter)
+{
+       int ret;
+
+       retv_if(NULL == iter, CTS_ERR_ARG_NULL);
+       retvm_if(iter->i_type <= CTS_ITER_NONE || CTS_ITER_MAX <= iter->i_type,
+                       CTS_ERR_ARG_INVALID, "iter is Invalid(type=%d", iter->i_type);
+
+       if (CTS_ITER_UPDATED_CONTACTS_AFTER_VER == iter->i_type)
+       {
+               retv_if(NULL == iter->info, CTS_ERR_ARG_INVALID);
+
+               if (NULL == iter->info->cursor)
+                       iter->info->cursor = iter->info->head;
+               else
+                       iter->info->cursor = iter->info->cursor->next;
+               if (NULL == iter->info->cursor || 0 == iter->info->cursor->id) {
+                       iter->info->cursor = NULL;
+                       cts_updated_contact_free_mempool(iter->info->head);
+                       iter->info->head = NULL;
+                       return CTS_ERR_FINISH_ITER;
+               }
+       }
+       else
+       {
+               ret = cts_stmt_step(iter->stmt);
+               if (CTS_TRUE != ret)
+               {
+                       if (CTS_SUCCESS != ret)
+                               ERR("cts_stmt_step() Failed(%d)", ret);
+                       cts_stmt_finalize(iter->stmt);
+                       iter->stmt = NULL;
+                       return CTS_ERR_FINISH_ITER;
+               }
+       }
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_iter_remove(CTSiter *iter)
+{
+       retv_if(NULL == iter, CTS_ERR_ARG_NULL);
+       retvm_if(iter->i_type <= CTS_ITER_NONE || CTS_ITER_MAX <= iter->i_type,
+                       CTS_ERR_ARG_INVALID, "iter is Invalid(type=%d", iter->i_type);
+
+       if (CTS_ITER_UPDATED_CONTACTS_AFTER_VER == iter->i_type) {
+               retv_if(NULL == iter->info, CTS_ERR_ARG_INVALID);
+               if (iter->info->head)
+                       cts_updated_contact_free_mempool(iter->info->head);
+               free(iter->info);
+       }
+       else {
+               cts_stmt_finalize(iter->stmt);
+       }
+
+       free(iter);
+       return CTS_SUCCESS;
+}
+
+static inline int cts_get_list(cts_get_list_op op_code, CTSiter *iter)
+{
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+       const char *display;
+
+       retv_if(NULL == iter, CTS_ERR_ARG_NULL);
+
+       iter->i_type = CTS_ITER_NONE;
+       iter->stmt = NULL;
+
+       switch (op_code)
+       {
+       case CTS_LIST_ALL_CONTACT:
+               iter->i_type = CTS_ITER_CONTACTS;
+
+               if (CTS_ORDER_NAME_LASTFIRST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       display = CTS_SCHEMA_DATA_NAME_REVERSE_LOOKUP;
+               else
+                       display = CTS_SCHEMA_DATA_NAME_LOOKUP;
+
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, data1, data2, data3, data5, B.addrbook_id, B.image0, %s "
+                               "FROM %s A, %s B ON A.contact_id = B.contact_id "
+                               "WHERE A.datatype = %d "
+                               "ORDER BY A.data1, A.%s",
+                               display, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                               CTS_DATA_NAME, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ALL_ADDRESSBOOK:
+               iter->i_type = CTS_ITER_ADDRESSBOOKS;
+               snprintf(query, sizeof(query),
+                               "SELECT addrbook_id, addrbook_name, acc_id, acc_type, mode "
+                               "FROM %s ORDER BY acc_id, addrbook_id",
+                               CTS_TABLE_ADDRESSBOOKS);
+
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ALL_GROUP:
+               iter->i_type = CTS_ITER_GROUPS;
+               snprintf(query, sizeof(query), "SELECT group_id, addrbook_id, group_name "
+                               "FROM %s ORDER BY addrbook_id, group_name COLLATE NOCASE",
+                               CTS_TABLE_GROUPS);
+
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ALL_CUSTOM_NUM_TYPE:
+               iter->i_type = CTS_ITER_ALL_CUSTOM_NUM_TYPE;
+               snprintf(query, sizeof(query), "SELECT id, name FROM %s WHERE class = %d",
+                               CTS_TABLE_CUSTOM_TYPES, CTS_TYPE_CLASS_NUM);
+
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_GROUPING_PLOG:
+               iter->i_type = CTS_ITER_GROUPING_PLOG;
+               snprintf(query, sizeof(query),
+                               "SELECT C.id, F.data1, F.data2, F.data3, F.data5, F.image0, C.number, "
+                               "C.log_type, C.log_time, C.data1, C.data2, C.contact_id, C.number_type "
+                               "FROM "
+                               "(SELECT A.id, A.number, A.log_type, A.log_time, A.data1, A.data2, "
+                               "MIN(B.contact_id) contact_id, B.data1 number_type "
+                               "FROM %s A LEFT JOIN %s B ON B.datatype = %d AND A.normal_num = B.data3 AND "
+                               "(A.related_id = B.contact_id OR A.related_id IS NULL OR "
+                               "NOT EXISTS (SELECT id FROM %s "
+                               "WHERE datatype = %d AND contact_id = A.related_id "
+                               "AND A.normal_num = data3)) "
+                               "GROUP BY A.id) C "
+                               "LEFT JOIN (SELECT D.contact_id, data1, data2, data3, data5, image0 "
+                               "FROM %s D, %s E ON D.datatype = %d AND D.contact_id = E.contact_id) F "
+                               "ON C.contact_id = F.contact_id "
+                               "GROUP BY F.data2, F.data3, F.data5, C.number "
+                               "ORDER BY C.log_time DESC",
+                               CTS_TABLE_PHONELOGS, CTS_TABLE_DATA, CTS_DATA_NUMBER, CTS_TABLE_DATA,
+                               CTS_DATA_NUMBER, CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_DATA_NAME);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_GROUPING_MSG_PLOG:
+               iter->i_type = CTS_ITER_GROUPING_PLOG;
+               snprintf(query, sizeof(query),
+                               "SELECT C.id, F.data1, F.data2, F.data3, F.data5, F.image0, C.number, "
+                               "C.log_type, C.log_time, C.data1, C.data2, C.contact_id, C.number_type "
+                               "FROM "
+                               "(SELECT A.id, A.number, A.log_type, A.log_time, A.data1, A.data2, "
+                               "MIN(B.contact_id) contact_id, B.data1 number_type "
+                               "FROM %s A LEFT JOIN %s B ON B.datatype = %d AND A.normal_num = B.data3 AND "
+                               "(A.related_id = B.contact_id OR A.related_id IS NULL OR "
+                               "NOT EXISTS (SELECT id FROM %s WHERE datatype = %d AND contact_id = A.related_id "
+                               "AND A.normal_num = data3)) "
+                               "WHERE A.log_type >= %d "
+                               "GROUP BY A.id) C "
+                               "LEFT JOIN (SELECT D.contact_id, data1, data2, data3, data5, image0 "
+                               "FROM %s D, %s E ON D.datatype = %d AND D.contact_id = E.contact_id) F "
+                               "ON C.contact_id = F.contact_id "
+                               "GROUP BY F.data2, F.data3, F.data5, C.number "
+                               "ORDER BY C.log_time DESC",
+                               CTS_TABLE_PHONELOGS, CTS_TABLE_DATA, CTS_DATA_NUMBER, CTS_TABLE_DATA, CTS_DATA_NUMBER,
+                               CTS_PLOG_TYPE_MMS_INCOMMING, CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_DATA_NAME);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_GROUPING_CALL_PLOG:
+               iter->i_type = CTS_ITER_GROUPING_PLOG;
+               snprintf(query, sizeof(query),
+                               "SELECT C.id, F.data1, F.data2, F.data3, F.data5, F.image0, C.number, "
+                               "C.log_type, C.log_time, C.data1, C.data2, C.contact_id, C.number_type "
+                               "FROM "
+                               "(SELECT A.id, A.number, A.log_type, A.log_time, A.data1, A.data2, "
+                               "MIN(B.contact_id) contact_id, B.data1 number_type "
+                               "FROM %s A LEFT JOIN %s B ON B.datatype = %d AND A.normal_num = B.data3 AND "
+                               "(A.related_id = B.contact_id OR A.related_id IS NULL OR "
+                               "NOT EXISTS (SELECT id FROM %s WHERE datatype = %d AND contact_id = A.related_id "
+                               "AND A.normal_num = data3)) "
+                               "WHERE A.log_type < %d "
+                               "GROUP BY A.id) C "
+                               "LEFT JOIN (SELECT D.contact_id, data1, data2, data3, data5, image0 "
+                               "FROM %s D, %s E ON D.datatype = %d AND D.contact_id = E.contact_id) F "
+                               "ON C.contact_id = F.contact_id "
+                               "GROUP BY F.data2, F.data3, F.data5, C.number "
+                               "ORDER BY C.log_time DESC",
+                               CTS_TABLE_PHONELOGS, CTS_TABLE_DATA, CTS_DATA_NUMBER, CTS_TABLE_DATA, CTS_DATA_NUMBER,
+                               CTS_PLOG_TYPE_MMS_INCOMMING, CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_DATA_NAME);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ALL_PLOG:
+               iter->i_type = CTS_ITER_GROUPING_PLOG;
+               snprintf(query, sizeof(query),
+                               "SELECT C.id, F.data1, F.data2, F.data3, F.data5, F.image0, C.number, "
+                               "C.log_type, C.log_time, C.data1, C.data2, C.contact_id, C.number_type "
+                               "FROM "
+                               "(SELECT A.id, A.number, A.log_type, A.log_time, A.data1, A.data2, "
+                               "MIN(B.contact_id) contact_id, B.data1 number_type "
+                               "FROM %s A LEFT JOIN %s B ON B.datatype = %d AND A.normal_num = B.data3 AND "
+                               "(A.related_id = B.contact_id OR A.related_id IS NULL OR "
+                               "NOT EXISTS (SELECT id FROM %s "
+                               "WHERE datatype = %d AND contact_id = A.related_id "
+                               "AND A.normal_num = data3)) "
+                               "GROUP BY A.id) C "
+                               "LEFT JOIN (SELECT D.contact_id, data1, data2, data3, data5, image0 "
+                               "FROM %s D, %s E ON D.datatype = %d AND D.contact_id = E.contact_id) F "
+                               "ON C.contact_id = F.contact_id "
+                               "ORDER BY C.log_time DESC",
+                               CTS_TABLE_PHONELOGS, CTS_TABLE_DATA, CTS_DATA_NUMBER, CTS_TABLE_DATA,
+                               CTS_DATA_NUMBER, CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_DATA_NAME);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ALL_MISSED_CALL:
+               iter->i_type = CTS_ITER_GROUPING_PLOG;
+               snprintf(query, sizeof(query),
+                               "SELECT C.id, F.data1, F.data2, F.data3, F.data5, F.image0, C.number, "
+                               "C.log_type, C.log_time, C.data1, C.data2, C.contact_id, C.number_type "
+                               "FROM "
+                               "(SELECT A.id, A.number, A.log_type, A.log_time, A.data1, A.data2, "
+                               "MIN(B.contact_id) contact_id, B.data1 number_type "
+                               "FROM %s A LEFT JOIN %s B ON B.datatype = %d AND A.normal_num = B.data3 AND "
+                               "(A.related_id = B.contact_id OR A.related_id IS NULL OR "
+                               "NOT EXISTS (SELECT id FROM %s "
+                               "WHERE datatype = %d AND contact_id = A.related_id "
+                               "AND A.normal_num = data3)) "
+                               "WHERE (A.log_type = %d OR A.log_type = %d) "
+                               "GROUP BY A.id) C "
+                               "LEFT JOIN (SELECT D.contact_id, data1, data2, data3, data5, image0 "
+                               "FROM %s D, %s E ON D.datatype = %d AND D.contact_id = E.contact_id) F "
+                               "ON C.contact_id = F.contact_id "
+                               "ORDER BY C.log_time DESC",
+                               CTS_TABLE_PHONELOGS, CTS_TABLE_DATA, CTS_DATA_NUMBER, CTS_TABLE_DATA, CTS_DATA_NUMBER,
+                               CTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN, CTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN,
+                               CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_DATA_NAME);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ALL_NUMBER_FAVORITE:
+               iter->i_type = CTS_ITER_ALL_NUM_FAVORITE;
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, D.image0, "
+                               "B.id, B.data1, B.data2 "
+                               "FROM %s A, %s B, %s C, %s D "
+                               "ON A.contact_id = B.contact_id AND B.id = C.related_id AND A.contact_id = D.contact_id "
+                               "WHERE A.datatype = %d AND B.datatype = %d AND C.type = %d "
+                               "ORDER BY C.favorite_prio",
+                               CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_FAVORITES, CTS_TABLE_CONTACTS,
+                               CTS_DATA_NAME, CTS_DATA_NUMBER, CTS_FAVOR_NUMBER);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ALL_CONTACT_FAVORITE:
+               iter->i_type = CTS_ITER_ALL_CONTACT_FAVORITE;
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, C.image0, B.id "
+                               "FROM %s A, %s B, %s C "
+                               "ON A.contact_id = B.related_id AND A.contact_id = C.contact_id "
+                               "WHERE A.datatype = %d AND B.type = %d "
+                               "ORDER BY B.favorite_prio",
+                               CTS_TABLE_DATA, CTS_TABLE_FAVORITES, CTS_TABLE_CONTACTS,
+                               CTS_DATA_NAME, CTS_FAVOR_CONTACT);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ALL_SPEEDDIAL:
+               iter->i_type = CTS_ITER_ALL_SPEEDDIAL;
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, D.image0, "
+                               "B.id, B.data1, B.data2, C.speed_num "
+                               "FROM %s A, %s B, %s C, %s D "
+                               "WHERE A.datatype = %d AND B.datatype = %d AND B.id = C.number_id "
+                               "AND A.contact_id = B.contact_id AND A.contact_id = D.contact_id "
+                               "ORDER BY C.speed_num",
+                               CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_SPEEDDIALS,
+                               CTS_TABLE_CONTACTS, CTS_DATA_NAME, CTS_DATA_NUMBER);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ALL_SDN:
+               iter->i_type = CTS_ITER_ALL_SDN;
+               snprintf(query, sizeof(query),"SELECT name, number FROM %s",
+                               CTS_TABLE_SIM_SERVICES);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ALL_CONTACT_HAD_NUMBER:
+               iter->i_type = CTS_ITER_CONTACTS;
+
+               if (CTS_ORDER_NAME_LASTFIRST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       display = CTS_SCHEMA_DATA_NAME_REVERSE_LOOKUP;
+               else
+                       display = CTS_SCHEMA_DATA_NAME_LOOKUP;
+
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.addrbook_id, B.image0, A.%s "
+                               "FROM %s A, %s B ON A.contact_id = B.contact_id "
+                               "WHERE A.datatype = %d AND B.default_num > 0 "
+                               "ORDER BY A.data1, A.%s",
+                               display, CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_DATA_NAME, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ALL_CONTACT_HAD_EMAIL:
+               iter->i_type = CTS_ITER_CONTACTS;
+               if (CTS_ORDER_NAME_LASTFIRST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       display = CTS_SCHEMA_DATA_NAME_REVERSE_LOOKUP;
+               else
+                       display = CTS_SCHEMA_DATA_NAME_LOOKUP;
+
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.addrbook_id, B.image0, A.%s "
+                               "FROM %s A, %s B ON A.contact_id = B.contact_id "
+                               "WHERE A.datatype = %d AND B.default_email > 0 "
+                               "ORDER BY A.data1, A.%s",
+                               display, CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_DATA_NAME, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ALL_EMAIL_NUMBER:
+               iter->i_type = CTS_ITER_NUMBERS_EMAILS;
+
+               if (CTS_ORDER_NAME_LASTFIRST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       display = CTS_SCHEMA_DATA_NAME_REVERSE_LOOKUP;
+               else
+                       display = CTS_SCHEMA_DATA_NAME_LOOKUP;
+
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0, C.addrbook_id, A.%s "
+                               "FROM %s A, %s B, %s C "
+                               "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                               "WHERE A.datatype = %d AND (B.datatype = %d OR B.datatype = %d) "
+                               "ORDER BY A.data1, A.%s",
+                               display, CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                               CTS_DATA_NAME, CTS_DATA_NUMBER, CTS_DATA_EMAIL, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_OFTEN_USED_CONTACT:
+               iter->i_type = CTS_ITER_CONTACTS;
+
+               if (CTS_ORDER_NAME_LASTFIRST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       display = CTS_SCHEMA_DATA_NAME_REVERSE_LOOKUP;
+               else
+                       display = CTS_SCHEMA_DATA_NAME_LOOKUP;
+
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, data1, data2, data3, data5, A.addrbook_id, A.image0, %s "
+                               "FROM %s A, %s B "
+                               "WHERE A.outgoing_count > %d AND B.datatype = %d "
+                               "AND B.contact_id = A.contact_id "
+                               "ORDER BY A.outgoing_count DESC, data1, %s",
+                               display, CTS_TABLE_CONTACTS, CTS_TABLE_DATA,
+                               CTS_OFTEN_USED_NUM, CTS_DATA_NAME, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ALL_NUMBER:
+               iter->i_type = CTS_ITER_NUMBERS_EMAILS;
+
+               if (CTS_ORDER_NAME_LASTFIRST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       display = CTS_SCHEMA_DATA_NAME_REVERSE_LOOKUP;
+               else
+                       display = CTS_SCHEMA_DATA_NAME_LOOKUP;
+
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0, C.addrbook_id, A.%s "
+                               "FROM %s A, %s B, %s C "
+                               "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                               "WHERE A.datatype = %d AND (B.datatype = %d) "
+                               "ORDER BY A.data1, A.%s",
+                               display, CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                               CTS_DATA_NAME, CTS_DATA_NUMBER, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       default:
+               ERR("Invalid parameter : The op_code(%d) is not supported", op_code);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_get_list(cts_get_list_op op_code, CTSiter **iter)
+{
+       int ret;
+       CTSiter *result;
+
+       retv_if(NULL == iter, CTS_ERR_ARG_NULL);
+
+       result = calloc(1, sizeof(CTSiter));
+       retvm_if(NULL == result, CTS_ERR_OUT_OF_MEMORY, "calloc() Failed");
+
+       ret = cts_get_list(op_code, result);
+       if (ret) {
+               ERR("cts_get_list() Failed(%d)", ret);
+               free(result);
+               return ret;
+       }
+
+       *iter = (CTSiter *)result;
+       return CTS_SUCCESS;
+}
+
+static inline int cts_get_list_with_str(cts_get_list_str_op op_code,
+               const char *search_value, CTSiter *iter)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+       const char *display;
+       char remake_val[CTS_SQL_MIN_LEN];
+
+       CTS_START_TIME_CHECK;
+
+       retv_if(NULL == iter, CTS_ERR_ARG_NULL);
+
+       iter->i_type = CTS_ITER_NONE;
+       iter->stmt = NULL;
+
+       retvm_if(NULL == search_value && CTS_LIST_PLOGS_OF_NUMBER != op_code,
+                       CTS_ERR_ARG_NULL, "The search_value is NULL");
+
+       switch ((int)op_code)
+       {
+       case CTS_LIST_PLOGS_OF_NUMBER:
+               iter->i_type = CTS_ITER_PLOGS_OF_NUMBER;
+               if (search_value && *search_value) {
+                       snprintf(query, sizeof(query),
+                                       "SELECT A.id, A.log_type, A.log_time, A.data1, A.data2, MIN(B.contact_id) "
+                                       "FROM %s A LEFT JOIN %s B ON A.normal_num = B.data3 AND B.datatype = %d AND "
+                                       "(A.related_id = B.contact_id OR A.related_id IS NULL OR "
+                                       "NOT EXISTS (SELECT id FROM %s "
+                                       "WHERE datatype = %d AND contact_id = A.related_id AND data3 = ?)) "
+                                       "WHERE A.number = ? "
+                                       "GROUP BY A.id "
+                                       "ORDER BY A.log_time DESC",
+                                       CTS_TABLE_PHONELOGS, CTS_TABLE_DATA, CTS_DATA_NUMBER, CTS_TABLE_DATA, CTS_DATA_NUMBER);
+               }
+               else {
+                       snprintf(query, sizeof(query),
+                                       "SELECT id, log_type, log_time, data1, data2, NULL "
+                                       "FROM %s WHERE number ISNULL ORDER BY id DESC", CTS_TABLE_PHONELOGS);
+               }
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               if (search_value) {
+                       const char *normal_num;
+                       ret = cts_clean_number(search_value, remake_val, sizeof(remake_val));
+                       retvm_if(ret <= 0, CTS_ERR_ARG_INVALID, "Number(%s) is invalid", search_value);
+
+                       normal_num = cts_normalize_number(remake_val);
+                       cts_stmt_bind_copy_text(stmt, 1, normal_num, strlen(normal_num));
+                       cts_stmt_bind_copy_text(stmt, 2, remake_val, strlen(remake_val));
+               }
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_CONTACTS_WITH_NAME:
+               retvm_if(CTS_SQL_MIN_LEN <= strlen(search_value), CTS_ERR_ARG_INVALID,
+                               "search_value is too long");
+               iter->i_type = CTS_ITER_CONTACTS_WITH_NAME;
+               memset(remake_val, 0x00, sizeof(remake_val));
+
+               ret = cts_normalize_str(search_value, remake_val, CTS_SQL_MIN_LEN);
+               retvm_if(ret < CTS_SUCCESS, ret, "cts_normalize_str() Failed(%d)", ret);
+
+               if (CTS_ORDER_NAME_LASTFIRST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       display = CTS_SCHEMA_DATA_NAME_REVERSE_LOOKUP;
+               else
+                       display = CTS_SCHEMA_DATA_NAME_LOOKUP;
+
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, data1, data2, data3, data5, B.addrbook_id, B.image0 "
+                               "FROM %s A, %s B ON A.contact_id = B.contact_id "
+                               "WHERE datatype = %d AND %s LIKE ('%%' || ? || '%%') "
+                               "ORDER BY data1, %s",
+                               CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_DATA_NAME, display, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               cts_stmt_bind_copy_text(stmt, 1, remake_val, strlen(remake_val));
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_NUMBERINFOS_WITH_NAME:
+               retvm_if(CTS_SQL_MIN_LEN <= strlen(search_value), CTS_ERR_ARG_INVALID,
+                               "search_value is too long");
+               iter->i_type = CTS_ITER_NUMBERINFOS;
+               memset(remake_val, 0x00, sizeof(remake_val));
+
+               ret = cts_normalize_str(search_value, remake_val, CTS_SQL_MIN_LEN);
+               retvm_if(ret < CTS_SUCCESS, ret, "cts_normalize_str() Failed(%d)", ret);
+
+               if (CTS_ORDER_NAME_LASTFIRST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       display = CTS_SCHEMA_DATA_NAME_REVERSE_LOOKUP;
+               else
+                       display = CTS_SCHEMA_DATA_NAME_LOOKUP;
+
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0 "
+                               "FROM %s A, %s B, %s C "
+                               "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                               "WHERE A.datatype = %d AND B.datatype = %d AND A.%s LIKE ('%%' || ? || '%%') "
+                               "ORDER BY A.data1, A.%s",
+                               CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                               CTS_DATA_NAME, CTS_DATA_NUMBER, display, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               cts_stmt_bind_copy_text(stmt, 1, remake_val, strlen(remake_val));
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_NUMBERINFOS_WITH_NUM:
+               iter->i_type = CTS_ITER_NUMBERINFOS;
+
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0 "
+                               "FROM %s A, %s B, %s C "
+                               "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                               "WHERE A.datatype = %d AND B.datatype = %d AND B.data2 LIKE ('%%' || ? || '%%') "
+                               "ORDER BY A.data1, A.%s",
+                               CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                               CTS_DATA_NAME, CTS_DATA_NUMBER, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               cts_stmt_bind_copy_text(stmt, 1, search_value, strlen(search_value));
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_EMAILINFOS_WITH_EMAIL:
+               iter->i_type = CTS_ITER_EMAILINFOS_WITH_EMAIL;
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0 "
+                               "FROM %s A, %s B, %s C "
+                               "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                               "WHERE A.datatype = %d AND B.datatype = %d AND B.data2 LIKE ('%%' || ? || '%%') "
+                               "ORDER BY A.data1, A.%s",
+                               CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                               CTS_DATA_NAME, CTS_DATA_EMAIL, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               cts_stmt_bind_copy_text(stmt, 1, search_value, strlen(search_value));
+               iter->stmt = stmt;
+               break;
+       case 10000: /* It is not supported. use only inhouse phone and message application */
+               retvm_if(CTS_SQL_MIN_LEN - 50 < strlen(search_value),
+                               CTS_ERR_ARG_INVALID, "search_value is too long");
+               iter->i_type = CTS_ITER_PLOGNUMBERS_WITH_NUM;
+               snprintf(query, sizeof(query),
+                               "SELECT number FROM %s WHERE number LIKE '%%%s%%' GROUP BY number",
+                               CTS_TABLE_PHONELOGS, search_value);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       default:
+               ERR("Invalid parameter : The op_code(%d) is not supported", op_code);
+               return CTS_ERR_ARG_INVALID;
+       }
+       CTS_START_TIME_CHECK;
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_get_list_with_str(cts_get_list_str_op op_code,
+               const char *search_value, CTSiter **iter)
+{
+       int ret;
+       CTSiter *result;
+
+       retv_if(NULL == iter, CTS_ERR_ARG_NULL);
+
+       result = calloc(1, sizeof(CTSiter));
+       retvm_if(NULL == result, CTS_ERR_OUT_OF_MEMORY, "calloc() Failed");
+
+       ret = cts_get_list_with_str(op_code, search_value, result);
+       if (ret) {
+               ERR("cts_get_list_with_str() Failed(%d)", ret);
+               free(result);
+               return ret;
+       }
+
+       *iter = (CTSiter *)result;
+       return CTS_SUCCESS;
+}
+
+static inline int cts_get_list_with_int(cts_get_list_int_op op_code,
+               unsigned int search_value, CTSiter *iter)
+{
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+       const char *display;
+
+       retv_if(NULL == iter, CTS_ERR_ARG_NULL);
+       iter->i_type = CTS_ITER_NONE;
+       iter->stmt = NULL;
+
+       if (CTS_ORDER_NAME_LASTFIRST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+               display = CTS_SCHEMA_DATA_NAME_REVERSE_LOOKUP;
+       else
+               display = CTS_SCHEMA_DATA_NAME_LOOKUP;
+
+       switch (op_code)
+       {
+       case CTS_LIST_MEMBERS_OF_GROUP_ID:
+               iter->i_type = CTS_ITER_CONTACTS;
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, data1, data2, data3, data5, B.addrbook_id, B.image0, %s "
+                               "FROM %s A, %s B WHERE datatype = %d AND A.contact_id IN "
+                               "(SELECT contact_id FROM %s WHERE group_id = %d) "
+                               "AND A.contact_id = B.contact_id "
+                               "ORDER BY data1, %s",
+                               display, CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_DATA_NAME,
+                               CTS_TABLE_GROUPING_INFO, search_value, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_NO_GROUP_MEMBERS_OF_ADDRESSBOOK_ID:
+               iter->i_type = CTS_ITER_CONTACTS;
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, data1, data2, data3, data5, A.addrbook_id, A.image0, %s "
+                               "FROM %s A, %s B ON A.contact_id = B.contact_id "
+                               "WHERE A.addrbook_id = %d AND NOT EXISTS "
+                               "(SELECT contact_id FROM %s WHERE contact_id=A.contact_id LIMIT 1) "
+                               "AND datatype = %d "
+                               "ORDER BY data1, %s",
+                               display, CTS_TABLE_CONTACTS, CTS_TABLE_DATA,
+                               search_value, CTS_TABLE_GROUPING_INFO, CTS_DATA_NAME,
+                               CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_MEMBERS_OF_ADDRESSBOOK_ID:
+               iter->i_type = CTS_ITER_CONTACTS;
+               snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, data1, data2, data3, data5, B.addrbook_id, B.image0, %s "
+                               "FROM %s A, %s B ON A.contact_id = B.contact_id "
+                               "WHERE datatype = %d AND B.addrbook_id = %d "
+                               "ORDER BY data1, %s",
+                               display, CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_DATA_NAME, search_value,
+                               CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_GROUPS_OF_ADDRESSBOOK_ID:
+               iter->i_type = CTS_ITER_GROUPS;
+               snprintf(query, sizeof(query),
+                               "SELECT group_id, %d, group_name "
+                               "FROM %s WHERE addrbook_id = %d "
+                               "ORDER BY group_name COLLATE NOCASE",
+                               search_value, CTS_TABLE_GROUPS, search_value);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_ADDRESSBOOKS_OF_ACCOUNT_ID:
+               iter->i_type = CTS_ITER_ADDRESSBOOKS;
+               snprintf(query, sizeof(query),
+                               "SELECT addrbook_id, addrbook_name, acc_id, acc_type, mode "
+                               "FROM %s WHERE acc_id = %d "
+                               "ORDER BY acc_id, addrbook_id",
+                               CTS_TABLE_ADDRESSBOOKS, search_value);
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               iter->stmt = stmt;
+               break;
+       default:
+               ERR("Invalid parameter : The op_code(%d) is not supported", op_code);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_get_list_with_int(cts_get_list_int_op op_code,
+               unsigned int search_value, CTSiter **iter)
+{
+       int ret;
+       CTSiter *result;
+
+       retv_if(NULL == iter, CTS_ERR_ARG_NULL);
+
+       result = calloc(1, sizeof(CTSiter));
+       retvm_if(NULL == result, CTS_ERR_OUT_OF_MEMORY, "calloc() Failed");
+
+       ret = cts_get_list_with_int(op_code, search_value, result);
+       if (ret) {
+               ERR("cts_get_list_with_int() Failed(%d)", ret);
+               free(result);
+               return ret;
+       }
+
+       *iter = (CTSiter *)result;
+       return CTS_SUCCESS;
+}
+
+static inline int cts_get_updated_contacts(int addressbook_id, int version,
+               CTSiter *iter)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+       updated_contact *result;
+
+       retv_if(NULL == iter, CTS_ERR_ARG_NULL);
+       retv_if(NULL == iter->info, CTS_ERR_ARG_INVALID);
+
+       iter->i_type = CTS_ITER_UPDATED_CONTACTS_AFTER_VER;
+       snprintf(query, sizeof(query),
+                       "SELECT %d, contact_id, changed_ver, created_ver FROM %s "
+                       "WHERE changed_ver > %d AND addrbook_id = %d "
+                       "UNION "
+                       "SELECT %d, contact_id, deleted_ver, -1 FROM %s "
+                       "WHERE deleted_ver > %d AND addrbook_id = %d",
+                       CTS_OPERATION_UPDATED, CTS_TABLE_CONTACTS, version, addressbook_id,
+                       CTS_OPERATION_DELETED, CTS_TABLE_DELETEDS, version, addressbook_id);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret)
+       {
+               warn_if(CTS_SUCCESS != ret, "cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_DB_RECORD_NOT_FOUND;
+       }
+
+       iter->info->head = result = cts_updated_contact_add_mempool();
+       do {
+               result->type = cts_stmt_get_int(stmt, 0);
+               result->id = cts_stmt_get_int(stmt, 1);
+               result->ver = cts_stmt_get_int(stmt, 2);
+               if (cts_stmt_get_int(stmt, 3) == result->ver || version < cts_stmt_get_int(stmt, 3))
+                       result->type = CTS_OPERATION_INSERTED;
+               if (NULL == result->next)
+                       result->next = cts_updated_contact_add_mempool();
+               result = result->next;
+       }while(CTS_TRUE == cts_stmt_step(stmt));
+
+       cts_stmt_finalize(stmt);
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_get_updated_contacts(int addressbook_id,
+               int version, CTSiter **iter)
+{
+       int ret;
+       CTSiter *result;
+
+       retv_if(NULL == iter, CTS_ERR_ARG_NULL);
+       retvm_if(version < 0, CTS_ERR_ARG_INVALID, "The version(%d) is invalid", version);
+
+       result = calloc(1, sizeof(CTSiter));
+       retvm_if(NULL == result, CTS_ERR_OUT_OF_MEMORY, "calloc() Failed");
+
+       result->info = calloc(1, sizeof(updated_contact_info));
+       if (NULL == result->info) {
+               ERR("calloc() Failed");
+               free(result);
+               return CTS_ERR_OUT_OF_MEMORY;
+       }
+
+       ret = cts_get_updated_contacts(addressbook_id, version, result);
+       if (ret) {
+               ERR("cts_get_updated_contacts() Failed(%d)", ret);
+               free(result->info);
+               free(result);
+               return ret;
+       }
+
+       *iter = (CTSiter *)result;
+       return CTS_SUCCESS;
+}
+
+static inline void cts_foreach_run(CTSiter *iter, cts_foreach_fn cb, void *data)
+{
+       while (CTS_SUCCESS == contacts_svc_iter_next(iter)) {
+               int ret;
+               CTSvalue *value;
+               value = contacts_svc_iter_get_info(iter);
+
+               ret = cb(value, data);
+               if (CTS_SUCCESS != ret) {
+                       ERR("cts_foreach_fn(%p) Failed(%d)", cb, ret);
+                       contacts_svc_value_free(value);
+                       break;
+               }
+
+               contacts_svc_value_free(value);
+       }
+       cts_stmt_finalize(iter->stmt);
+}
+
+API int contacts_svc_list_foreach(cts_get_list_op op_code,
+               cts_foreach_fn cb, void *user_data)
+{
+       int ret;
+       CTSiter iter = {0};
+
+       ret = cts_get_list(op_code, &iter);
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_get_list() Failed(%d)", ret);
+
+       cts_foreach_run(&iter, cb, user_data);
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_list_with_int_foreach(cts_get_list_int_op op_code,
+               unsigned int search_value, cts_foreach_fn cb, void *user_data)
+{
+       int ret;
+       CTSiter iter = {0};
+
+       ret = cts_get_list_with_int(op_code, search_value, &iter);
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_get_list_with_int() Failed(%d)", ret);
+
+       cts_foreach_run(&iter, cb, user_data);
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_list_with_str_foreach(cts_get_list_str_op op_code,
+               const char *search_value, cts_foreach_fn cb, void *user_data)
+{
+       int ret;
+       CTSiter iter = {0};
+
+       ret = cts_get_list_with_str(op_code, search_value, &iter);
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_get_list_with_str() Failed(%d)", ret);
+
+       cts_foreach_run(&iter, cb, user_data);
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_list_filter_free(CTSfilter *filter)
+{
+       retv_if(NULL == filter, CTS_ERR_ARG_NULL);
+
+       free(filter->search_val);
+       free(filter);
+       return CTS_SUCCESS;
+}
+
+static inline int cts_filter_parse_args(va_list args, int type, CTSfilter *ret)
+{
+       while (type) {
+               switch (type) {
+               case CTS_LIST_FILTER_NONE:
+                       break;
+               case CTS_LIST_FILTER_ADDRESBOOK_ID_INT:
+                       ret->addrbook_on = true;
+                       ret->addrbook_id = va_arg(args, int);
+                       break;
+               case CTS_LIST_FILTER_GROUP_ID_INT:
+                       ret->group_on = true;
+                       ret->group_id = va_arg(args, int);
+                       break;
+               case CTS_LIST_FILTER_LIMIT_INT:
+                       ret->limit_on = true;
+                       ret->limit = va_arg(args, int);
+                       break;
+               case CTS_LIST_FILTER_OFFSET_INT:
+                       ret->offset_on = true;
+                       ret->offset = va_arg(args, int);
+                       break;
+               default:
+                       ERR("Invalid type. Your type(%d) is not supported.", type);
+                       return CTS_ERR_ARG_INVALID;
+               }
+               type = va_arg(args, int);
+       }
+
+       retvm_if(ret->offset_on && !ret->limit_on, CTS_ERR_ARG_INVALID, "OFFSET is depends on LIMIT");
+
+       return CTS_SUCCESS;
+}
+
+enum {
+       CTS_FILTER_TYPE_NONE,
+       CTS_FILTER_TYPE_INT,
+       CTS_FILTER_TYPE_STR,
+};
+
+API CTSfilter* contacts_svc_list_str_filter_new(cts_str_filter_op list_type,
+               const char *search_value, cts_filter_type first_type, ...)
+{
+       int ret;
+       CTSfilter *ret_val;
+       va_list args;
+
+       retvm_if(NULL == search_value, NULL, "The parameter(search_value) is NULL");
+       retvm_if(CTS_LIST_FILTER_NONE == first_type, NULL,
+                       "filter constraint is missing(use contacts_svc_get_list_with_str()");
+
+       ret_val = calloc(1, sizeof(CTSfilter));
+       ret_val->type = CTS_FILTER_TYPE_STR;
+       ret_val->list_type = list_type;
+       ret_val->search_val = strdup(search_value);
+
+       va_start(args, first_type);
+       ret = cts_filter_parse_args(args, first_type, ret_val);
+       va_end(args);
+
+       if (ret) {
+               contacts_svc_list_filter_free(ret_val);
+               return NULL;
+       }
+
+       return (CTSfilter *)ret_val;
+}
+
+API CTSfilter* contacts_svc_list_filter_new(cts_filter_op list_type, cts_filter_type first_type, ...)
+{
+       int ret;
+       CTSfilter *ret_val;
+       va_list args;
+
+       retvm_if(CTS_LIST_FILTER_NONE == first_type, NULL,
+                       "filter constraint is missing(use contacts_svc_get_list()");
+
+       ret_val = calloc(1, sizeof(CTSfilter));
+       ret_val = CTS_FILTER_TYPE_NONE;
+       ret_val->list_type = list_type;
+
+       va_start(args, first_type);
+       ret = cts_filter_parse_args(args, first_type, ret_val);
+       va_end(args);
+
+       if (ret) {
+               contacts_svc_list_filter_free(ret_val);
+               return NULL;
+       }
+
+       return (CTSfilter *)ret_val;
+}
+
+static int cts_list_with_str_make_query(CTSfilter *filter, CTSiter *iter)
+{
+       int ret;
+       cts_stmt stmt;
+       const char *display;
+       char query[CTS_SQL_MAX_LEN] = {0};
+       char remake_val[CTS_SQL_MIN_LEN] = {0};
+
+       retvm_if(NULL == filter->search_val,
+                       CTS_ERR_ARG_INVALID, "The parameter(filter) doesn't have search_val");
+
+       if (CTS_ORDER_NAME_LASTFIRST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+               display = CTS_SCHEMA_DATA_NAME_REVERSE_LOOKUP;
+       else
+               display = CTS_SCHEMA_DATA_NAME_LOOKUP;
+
+       switch (filter->list_type) {
+       case CTS_LIST_PLOGS_OF_NUMBER:
+               iter->i_type = CTS_ITER_PLOGS_OF_NUMBER;
+               if (filter->search_val && *filter->search_val) {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT A.id, A.log_type, A.log_time, A.data1, A.data2, MIN(B.contact_id) "
+                                       "FROM %s A LEFT JOIN %s B ON A.normal_num = B.data3 AND B.datatype = %d AND "
+                                       "(A.related_id = B.contact_id OR A.related_id IS NULL OR "
+                                       "NOT EXISTS (SELECT id FROM %s "
+                                       "WHERE datatype = %d AND contact_id = A.related_id AND data3 = ?)) "
+                                       "WHERE A.number = ? "
+                                       "GROUP BY A.id "
+                                       "ORDER BY A.log_time DESC",
+                                       CTS_TABLE_PHONELOGS, CTS_TABLE_DATA, CTS_DATA_NUMBER, CTS_TABLE_DATA, CTS_DATA_NUMBER);
+               }
+               else {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT id, log_type, log_time, data1, data2, NULL "
+                                       "FROM %s WHERE number ISNULL ORDER BY id DESC", CTS_TABLE_PHONELOGS);
+               }
+               if (filter->limit_on) {
+                       ret += snprintf(query+ret, sizeof(query)-ret, " LIMIT %d ", filter->limit);
+                       if (filter->offset_on)
+                               ret += snprintf(query+ret, sizeof(query)-ret, ", %d", filter->offset);
+               }
+
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               if (filter->search_val) {
+                       const char *normal_num;
+                       ret = cts_clean_number(filter->search_val, remake_val, sizeof(remake_val));
+                       retvm_if(ret <= 0, CTS_ERR_ARG_INVALID, "Number(%s) is invalid", filter->search_val);
+
+                       normal_num = cts_normalize_number(remake_val);
+                       cts_stmt_bind_copy_text(stmt, 1, normal_num, strlen(normal_num));
+                       cts_stmt_bind_copy_text(stmt, 2, remake_val, strlen(remake_val));
+               }
+               iter->stmt = stmt;
+               break;
+       case CTS_LIST_CONTACTS_WITH_NAME:
+               retvm_if(CTS_SQL_MIN_LEN <= strlen(filter->search_val), CTS_ERR_ARG_INVALID,
+                               "search_value is too long");
+               iter->i_type = CTS_ITER_CONTACTS_WITH_NAME;
+               memset(remake_val, 0x00, sizeof(remake_val));
+
+               ret = cts_normalize_str(filter->search_val, remake_val, CTS_SQL_MIN_LEN);
+               retvm_if(ret < CTS_SUCCESS, ret, "cts_normalize_str() Failed(%d)", ret);
+
+               if (filter->addrbook_on) {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT A.contact_id, data1, data2, data3, data5, B.addrbook_id, B.image0 "
+                                       "FROM %s A, %s B ON A.contact_id = B.contact_id "
+                                       "WHERE datatype = %d AND B.addrbook_id = %d AND %s LIKE ('%%' || ? || '%%') "
+                                       "ORDER BY data1, %s",
+                                       CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_DATA_NAME, filter->addrbook_id,
+                                       display, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               } else if (filter->group_on) {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT A.contact_id, data1, data2, data3, data5, B.addrbook_id, B.image0 "
+                                       "FROM %s A, %s B ON A.contact_id = B.contact_id "
+                                       "WHERE datatype = %d AND %s LIKE ('%%' || ? || '%%') "
+                                       "AND contact_id IN (SELECT contact_id FROM %s WHERE group_id = %d) "
+                                       "ORDER BY data1, %s",
+                                       CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_DATA_NAME, display,
+                                       CTS_TABLE_GROUPING_INFO, filter->group_id,
+                                       CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               } else {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT A.contact_id, data1, data2, data3, data5, B.addrbook_id, B.image0 "
+                                       "FROM %s A, %s B ON A.contact_id = B.contact_id "
+                                       "WHERE datatype = %d AND %s LIKE ('%%' || ? || '%%') "
+                                       "ORDER BY data1, %s",
+                                       CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_DATA_NAME, display,
+                                       CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               }
+
+               if (filter->limit_on) {
+                       ret += snprintf(query+ret, sizeof(query)-ret, " LIMIT %d ", filter->limit);
+                       if (filter->offset_on)
+                               ret += snprintf(query+ret, sizeof(query)-ret, ", %d", filter->offset);
+               }
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               cts_stmt_bind_copy_text(stmt, 1, remake_val, strlen(remake_val));
+               break;
+       case CTS_LIST_NUMBERINFOS_WITH_NAME:
+               retvm_if(CTS_SQL_MIN_LEN <= strlen(filter->search_val), CTS_ERR_ARG_INVALID,
+                               "search_value is too long");
+               iter->i_type = CTS_ITER_NUMBERINFOS;
+               memset(remake_val, 0x00, sizeof(remake_val));
+
+               ret = cts_normalize_str(filter->search_val, remake_val, CTS_SQL_MIN_LEN);
+               retvm_if(ret < CTS_SUCCESS, ret, "cts_normalize_str() Failed(%d)", ret);
+
+               if (filter->addrbook_on) {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0 "
+                                       "FROM %s A, %s B, %s C "
+                                       "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                                       "WHERE A.datatype = %d AND A.datatype = %d "
+                                       "AND C.addrbook_id = %d AND A.%s LIKE ('%%' || ? || '%%') "
+                                       "ORDER BY A.data1, A.%s",
+                                       CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                                       CTS_DATA_NAME, CTS_DATA_NUMBER,
+                                       filter->addrbook_id, display, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               } else if (filter->group_on) {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0 "
+                                       "FROM %s A, %s B, %s C "
+                                       "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                                       "WHERE A.datatype = %d AND B.datatype = %d AND A.%s LIKE ('%%' || ? || '%%') "
+                                       "AND A.contact_id IN "
+                                       "(SELECT contact_id FROM %s WHERE group_id = %d) "
+                                       "ORDER BY A.data1, A.%s",
+                                       CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                                       CTS_DATA_NAME, CTS_DATA_NUMBER, display,
+                                       CTS_TABLE_GROUPING_INFO, filter->group_id, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               } else {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0 "
+                                       "FROM %s A, %s B, %s C "
+                                       "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                                       "WHERE A.datatype = %d AND B.datatype = %d AND A.%s LIKE ('%%' || ? || '%%') "
+                                       "ORDER BY A.data1, A.%s",
+                                       CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                                       CTS_DATA_NAME, CTS_DATA_NUMBER,
+                                       display, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               }
+               if (filter->limit_on) {
+                       ret += snprintf(query+ret, sizeof(query)-ret, " LIMIT %d ", filter->limit);
+                       if (filter->offset_on)
+                               ret += snprintf(query+ret, sizeof(query)-ret, ", %d", filter->offset);
+               }
+
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               cts_stmt_bind_copy_text(stmt, 1, remake_val, strlen(remake_val));
+               break;
+       case CTS_LIST_NUMBERINFOS_WITH_NUM:
+               iter->i_type = CTS_ITER_NUMBERINFOS;
+
+               if (filter->addrbook_on) {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0 "
+                                       "FROM %s A, %s B, %s C "
+                                       "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                                       "WHERE A.datatype = %d AND B.datatype = %d "
+                                       "AND C.addrbook_id = %d AND B.data2 LIKE ('%%' || ? || '%%') "
+                                       "ORDER BY A.data1, A.%s",
+                                       CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                                       CTS_DATA_NAME, CTS_DATA_NUMBER,
+                                       filter->addrbook_id, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               } else if (filter->group_on) {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0 "
+                                       "FROM %s A, %s B, %s C "
+                                       "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                                       "WHERE A.datatype = %d AND B.datatype = %d AND B.data2 LIKE ('%%' || ? || '%%') "
+                                       "AND A.contact_id IN (SELECT contact_id FROM %s WHERE group_id = %d) "
+                                       "ORDER BY A.data1, A.%s",
+                                       CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                                       CTS_DATA_NAME, CTS_DATA_NUMBER,
+                                       CTS_TABLE_GROUPING_INFO, filter->group_id, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               } else {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0 "
+                                       "FROM %s A, %s B, %s C "
+                                       "ON A.contact_id = B.contact_id AND A.contact_id = C.conatct_id "
+                                       "WHERE B.data2 LIKE ('%%' || ? || '%%') "
+                                       "AND A.datatype = %d AND B.datatype = %d "
+                                       "ORDER BY A.data1, A.%s",
+                                       CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                                       CTS_DATA_NAME, CTS_DATA_NUMBER, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               }
+               if (filter->limit_on) {
+                       ret += snprintf(query+ret, sizeof(query)-ret, " LIMIT %d ", filter->limit);
+                       if (filter->offset_on)
+                               ret += snprintf(query+ret, sizeof(query)-ret, ", %d", filter->offset);
+               }
+
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               cts_stmt_bind_copy_text(stmt, 1, filter->search_val, strlen(filter->search_val));
+               break;
+       case CTS_LIST_EMAILINFOS_WITH_EMAIL:
+               iter->i_type = CTS_ITER_EMAILINFOS_WITH_EMAIL;
+
+               if (filter->addrbook_on) {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0 "
+                                       "FROM %s A, %s B, %s C "
+                                       "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                                       "WHERE A.datatype = %d AND B.datatype = %d AND C.addrbook_id = %d "
+                                       "AND B.data2 LIKE ('%%' || ? || '%%') "
+                                       "ORDER BY A.data1, A.%s",
+                                       CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                                       CTS_DATA_NAME, CTS_DATA_NUMBER, filter->addrbook_id,
+                                       CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               } else if (filter->group_on) {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0 "
+                                       "FROM %s A, %s B, %s C "
+                                       "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                                       "WHERE A.datatype = %d AND B.datatype = %d AND "
+                                       "B.data2 LIKE ('%%' || ? || '%%') AND A.contact_id IN "
+                                       "(SELECT contact_id FROM %s WHERE group_id = %d) "
+                                       "ORDER BY A.data1, A.%s",
+                                       CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                                       CTS_DATA_NAME, CTS_DATA_NUMBER,
+                                       CTS_TABLE_GROUPING_INFO, filter->group_id,
+                                       CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               } else {
+                       ret = snprintf(query, sizeof(query),
+                                       "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0 "
+                                       "FROM %s A, %s B, %s C "
+                                       "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                                       "WHERE A.datatype = %d AND B.datatype = %d AND B.data2 LIKE ('%%' || ? || '%%') "
+                                       "ORDER BY A.data1, A.%s",
+                                       CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                                       CTS_DATA_NAME, CTS_DATA_EMAIL,
+                                       CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+               }
+               if (filter->limit_on) {
+                       ret += snprintf(query+ret, sizeof(query)-ret, " LIMIT %d ", filter->limit);
+                       if (filter->offset_on)
+                               ret += snprintf(query+ret, sizeof(query)-ret, ", %d", filter->offset);
+               }
+
+               stmt = cts_query_prepare(query);
+               retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+               cts_stmt_bind_copy_text(stmt, 1, filter->search_val, strlen(filter->search_val));
+               break;
+       default:
+               ERR("Invalid parameter : The op_code(%d) is not supported", filter->list_type);
+               return CTS_ERR_ARG_INVALID;
+       }
+       iter->stmt = stmt;
+
+       return CTS_SUCCESS;
+}
+
+#ifdef CTS_DEPRECATED
+API int contacts_svc_get_list_with_filter(CTSfilter *filter, CTSiter **iter)
+{
+       int ret;
+       CTSiter *result;
+
+       retv_if(NULL == filter, CTS_ERR_ARG_NULL);
+       retv_if(NULL == iter, CTS_ERR_ARG_NULL);
+
+       if (CTS_FILTER_TYPE_STR == filter->type) {
+               result = calloc(1, sizeof(CTSiter));
+               retvm_if(NULL == result, CTS_ERR_OUT_OF_MEMORY, "calloc() Failed");
+
+               ret = cts_list_with_str_make_query(filter, result);
+               if (ret) {
+                       ERR("cts_list_with_str_make_query() Failed(%d)", ret);
+                       free(result);
+                       return ret;
+               }
+       } else {
+               ERR("Invalid CTSfilter(type = %d)", filter->type);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       return CTS_SUCCESS;
+}
+#endif
+
+API int contacts_svc_list_with_filter_foreach(CTSfilter *filter,
+               cts_foreach_fn cb, void *user_data)
+{
+       int ret;
+       CTSiter iter = {0};
+
+       if (CTS_FILTER_TYPE_STR == filter->type) {
+               ret = cts_list_with_str_make_query(filter, &iter);
+               retvm_if(CTS_SUCCESS != ret, ret, "contacts_svc_get_list_with_filter() Failed(%d)", ret);
+       } else {
+               ERR("Invalid CTSfilter(type = %d)", filter->type);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       cts_foreach_run(&iter, cb, user_data);
+
+       return CTS_SUCCESS;
+}
+
+static inline bool cts_is_number(const char *str)
+{
+       int i;
+
+       for (i=0;i<strlen(str);i++)
+       {
+               switch (str[i])
+               {
+               case '0' ... '9':
+               case 'p':
+               case 'w':
+               case '+':
+                       break;
+               default:
+                       return false;
+               }
+       }
+       return true;
+}
+
+API int contacts_svc_smartsearch_excl(const char *search_str, int limit, int offset,
+               cts_foreach_fn cb, void *user_data)
+{
+       int ret, len;
+       CTSiter iter = {0};
+       const char *display;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN];
+       char remake_name[CTS_SQL_MIN_LEN];
+
+       retv_if(NULL == search_str, CTS_ERR_ARG_NULL);
+       retvm_if(CTS_SQL_MIN_LEN <= strlen(search_str), CTS_ERR_ARG_INVALID,
+                       "search_str is too long");
+
+       iter.i_type = CTS_ITER_NUMBERINFOS;
+
+       if (CTS_ORDER_NAME_LASTFIRST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+               display = CTS_SCHEMA_DATA_NAME_REVERSE_LOOKUP;
+       else
+               display = CTS_SCHEMA_DATA_NAME_LOOKUP;
+
+       if (cts_is_number(search_str)) {
+               len = snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, B.data2, C.image0 "
+                               "FROM %s A, %s B, %s C "
+                               "ON A.contact_id = B.contact_id AND A.contact_id = C.contact_id "
+                               "WHERE A.datatype = %d AND B.datatype = %d "
+                               "AND (B.data2 LIKE '%%%s%%' OR A.%s LIKE ('%%' || ? || '%%')) "
+                               "ORDER BY A.data1, A.%s",
+                               CTS_TABLE_DATA, CTS_TABLE_DATA, CTS_TABLE_CONTACTS,
+                               CTS_DATA_NAME, CTS_DATA_NUMBER,
+                               search_str, display, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+       }
+       else {
+               len = snprintf(query, sizeof(query),
+                               "SELECT A.contact_id, A.data1, A.data2, A.data3, A.data5, D.data2, D.image0 "
+                               "FROM %s A "
+                               "LEFT JOIN (%s B, %s C ON B.default_num = C.id AND C.datatype = %d ) D "
+                               "ON A.contact_id = D.contact_id "
+                               "WHERE A.datatype = %d AND A.%s LIKE ('%%' || ? || '%%') "
+                               "ORDER BY A.data1, A.%s",
+                               CTS_TABLE_DATA, CTS_TABLE_CONTACTS, CTS_TABLE_DATA,
+                               CTS_DATA_NUMBER, CTS_DATA_NAME, display, CTS_SCHEMA_DATA_NAME_SORTING_KEY);
+       }
+
+       if (limit)
+               snprintf(query+len, sizeof(query)-len, " LIMIT %d OFFSET %d", limit, offset);
+
+       ret = cts_normalize_str(search_str, remake_name, sizeof(remake_name));
+       retvm_if(ret < CTS_SUCCESS, ret, "cts_normalize_str() Failed(%d)", ret);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       cts_stmt_bind_copy_text(stmt, 1, remake_name, strlen(remake_name));
+       iter.stmt = stmt;
+
+       cts_foreach_run(&iter, cb, user_data);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_group_get_relation_changes(int addressbook_id, int version,
+               CTSiter *iter)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+       updated_contact *result;
+
+       retv_if(NULL == iter, CTS_ERR_ARG_NULL);
+       retv_if(NULL == iter->info, CTS_ERR_ARG_INVALID);
+
+       iter->i_type = CTS_ITER_UPDATED_CONTACTS_AFTER_VER;
+       snprintf(query, sizeof(query),
+                       "SELECT group_id, type, ver FROM %s, %s USING (group_id) "
+                       "WHERE ver > %d AND addrbook_id = %d ",
+                       "group_relations_log", CTS_TABLE_GROUPS,
+                       version, addressbook_id);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret)
+       {
+               warn_if(CTS_SUCCESS != ret, "cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_DB_RECORD_NOT_FOUND;
+       }
+
+       iter->info->head = result = cts_updated_contact_add_mempool();
+       do {
+               result->id = cts_stmt_get_int(stmt, 0);
+               result->type = cts_stmt_get_int(stmt, 1);
+               result->ver = cts_stmt_get_int(stmt, 2);
+
+               if (NULL == result->next)
+                       result->next = cts_updated_contact_add_mempool();
+               result = result->next;
+       }while(CTS_TRUE == cts_stmt_step(stmt));
+
+       cts_stmt_finalize(stmt);
+
+       return CTS_SUCCESS;
+}
diff --git a/src/cts-list.h b/src/cts-list.h
new file mode 100755 (executable)
index 0000000..93a3356
--- /dev/null
@@ -0,0 +1,612 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_LIST_H__
+#define __CTS_LIST_H__
+
+#include "cts-sqlite.h"
+
+enum
+{
+       CTS_ITER_NONE,
+       CTS_ITER_CONTACTS,
+       CTS_ITER_ALL_CUSTOM_NUM_TYPE,
+       CTS_ITER_GROUPING_PLOG,
+       CTS_ITER_ALL_CONTACT_FAVORITE,
+       CTS_ITER_ALL_NUM_FAVORITE,
+       CTS_ITER_ALL_SPEEDDIAL,
+       CTS_ITER_ALL_SDN,
+       CTS_ITER_PLOGS_OF_NUMBER,
+       CTS_ITER_PLOGNUMBERS_WITH_NUM,
+       CTS_ITER_CONTACTS_WITH_NAME,
+       CTS_ITER_NUMBERINFOS,
+       CTS_ITER_EMAILINFOS_WITH_EMAIL,
+       CTS_ITER_NUMBERS_EMAILS,
+       CTS_ITER_GROUPS,
+       CTS_ITER_ADDRESSBOOKS,
+       CTS_ITER_EMAILS_OF_CONTACT_ID,
+       CTS_ITER_NUMBERS_OF_CONTACT_ID,
+       CTS_ITER_UPDATED_CONTACTS_AFTER_VER,
+       CTS_ITER_MAX
+};
+
+typedef struct _updated_contact {
+       int type;
+       int id;
+       int ver;
+       struct _updated_contact *next;
+}updated_contact;
+
+typedef struct {
+       updated_contact *head;
+       updated_contact *cursor;
+}updated_contact_info;
+
+struct _cts_iter {
+       int i_type;
+       cts_stmt stmt;
+       updated_contact_info *info;
+};
+
+struct cts_filter {
+       int type;
+       int list_type;
+       char *search_val;
+       bool addrbook_on;
+       bool group_on;
+       bool limit_on;
+       bool offset_on;
+       int addrbook_id;
+       int group_id;
+       int limit;
+       int offset;
+};
+
+//<!--
+/**
+ * @defgroup   CONTACTS_SVC_LIST List handling
+ * @ingroup    CONTACTS_SVC
+ * @addtogroup CONTACTS_SVC_LIST
+ * @{
+ *
+ * This interface provides methods to handle the List.
+ *
+ * List is handled by iterator. The iterator is same to handle's cursor of Sqlite3.
+ * While an iterator is in use, all attempts to write in this or some other process
+ * will be blocked. Parallel reads are supported.
+ *
+ */
+
+/**
+ * CTSiter is an opaque type.
+ * Iterator can get by contacts_svc_get_list(), contacts_svc_get_list_with_int(),
+ * contacts_svc_get_list_with_str(), contacts_svc_get_list_with_filter(), contacts_svc_get_updated_contacts().
+ * \n And Iterator can handle by contacts_svc_iter_next(), contacts_svc_iter_remove(), contacts_svc_iter_get_info().
+ */
+typedef struct _cts_iter CTSiter;
+
+/**
+ * CTSiter is an opaque type, it must be
+ * used via accessor functions.
+ * @see contacts_svc_list_filter_new(), contacts_svc_list_str_filter_new(), contacts_svc_list_filter_free()
+ */
+typedef struct cts_filter CTSfilter;
+
+//////////////////// read only value ////////////////////
+//////////////////// List row info ////////////////////
+/**
+ * Phone Log List
+ * For #CTS_LIST_PLOGS_OF_NUMBER, it supports CTS_LIST_PLOG_ID_INT, CTS_LIST_PLOG_LOG_TIME_INT,
+ * CTS_LIST_PLOG_LOG_TYPE_INT, CTS_LIST_PLOG_DURATION_INT(or CTS_LIST_PLOG_MSGID_INT), CTS_LIST_PLOG_SHORTMSG_STR
+ * and CTS_LIST_PLOG_RELATED_ID_INT.
+ */
+enum PHONELOGLIST{
+       CTS_LIST_PLOG_ID_INT,/**< . */
+       CTS_LIST_PLOG_NUM_TYPE_INT,/**< you can use #NUMBERTYPE or contacts_svc_find_custom_type(). */
+       CTS_LIST_PLOG_FIRST_NAME_STR,/**< . */
+       CTS_LIST_PLOG_LAST_NAME_STR,/**< . */
+       CTS_LIST_PLOG_DISPLAY_NAME_STR,/**< . */
+       CTS_LIST_PLOG_NUMBER_STR,/**< . */
+       CTS_LIST_PLOG_IMG_PATH_STR,/**< . */
+       CTS_LIST_PLOG_LOG_TIME_INT,/**< The time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds. */
+       CTS_LIST_PLOG_LOG_TYPE_INT,/**< . */
+       CTS_LIST_PLOG_DURATION_INT,/**< seconds */
+       CTS_LIST_PLOG_MSGID_INT,/**< . */
+       CTS_LIST_PLOG_SHORTMSG_STR,/**< . */
+       CTS_LIST_PLOG_RELATED_ID_INT/**< contact id */
+};
+
+/**
+ * Contact List
+ */
+enum CONTACTLIST{
+       CTS_LIST_CONTACT_ID_INT,/**< . */
+       CTS_LIST_CONTACT_IMG_PATH_STR,/**< . */
+       CTS_LIST_CONTACT_FIRST_STR,/**< . */
+       CTS_LIST_CONTACT_LAST_STR,/**< . */
+       CTS_LIST_CONTACT_DISPLAY_STR,/**< . */
+       CTS_LIST_CONTACT_NUM_OR_EMAIL_STR,/**< optional. related with #CTS_LIST_ALL_EMAIL_NUMBER */
+       CTS_LIST_CONTACT_NORMALIZED_STR,/**< optional */
+       CTS_LIST_CONTACT_ADDRESSBOOK_ID_INT,/**< . */
+};
+
+/**
+ * Number List
+ */
+enum NUMBERLIST{
+       CTS_LIST_NUM_CONTACT_ID_INT,/**< . */
+       CTS_LIST_NUM_CONTACT_IMG_PATH_STR,/**< . */
+       CTS_LIST_NUM_CONTACT_FIRST_STR,/**< . */
+       CTS_LIST_NUM_CONTACT_LAST_STR,/**< . */
+       CTS_LIST_NUM_CONTACT_DISPLAY_STR,/**< . */
+       CTS_LIST_NUM_NUMBER_STR /**< . */
+};
+
+/**
+ * Email List
+ */
+enum EMAILLIST{
+       CTS_LIST_EMAIL_CONTACT_ID_INT,/**< . */
+       CTS_LIST_EMAIL_CONTACT_IMG_PATH_STR,/**< . */
+       CTS_LIST_EMAIL_CONTACT_FIRST_STR,/**< . */
+       CTS_LIST_EMAIL_CONTACT_LAST_STR,/**< . */
+       CTS_LIST_EMAIL_CONTACT_DISPLAY_STR,/**< . */
+       CTS_LIST_EMAIL_ADDR_STR /**< . */
+};
+
+
+/**
+ * Change List
+ */
+enum CHANGELIST{
+       CTS_LIST_CHANGE_ID_INT,/**< . */
+       CTS_LIST_CHANGE_TYPE_INT, /**< #CTS_OPERATION_UPDATED, #CTS_OPERATION_DELETED, #CTS_OPERATION_INSERTED */
+       CTS_LIST_CHANGE_VER_INT,/**< The version when this contact is changed */
+};
+
+enum {
+       CTS_OPERATION_UPDATED, /**< . */
+       CTS_OPERATION_DELETED, /**< . */
+       CTS_OPERATION_INSERTED /**< . */
+};
+
+/**
+ * Addressbook List
+ * Though it is same with ADDRESSBOOKVALUE, Use this for list
+ */
+enum ADDRESSBOOKLIST{
+       CTS_LIST_ADDRESSBOOK_ID_INT, /**< . */
+       CTS_LIST_ADDRESSBOOK_NAME_STR, /**< . */
+       CTS_LIST_ADDRESSBOOK_ACC_ID_INT, /**< The related account id */
+       CTS_LIST_ADDRESSBOOK_ACC_TYPE_INT, /**< #ADDRESSBOOKTYPE */
+       CTS_LIST_ADDRESSBOOK_MODE_INT, /**< #ADDRESSBOOKPERMISSION */
+};
+
+/**
+ * Custom Number Type List
+ */
+enum CUSTOMNUMTYPELIST{
+       CTS_LIST_CUSTOM_NUM_TYPE_ID_INT,/**< . */
+       CTS_LIST_CUSTOM_NUM_TYPE_NAME_STR,/**< . */
+};
+
+
+/**
+ * Group List
+ */
+enum GROUPLIST{
+       CTS_LIST_GROUP_ID_INT,/**< . */
+       CTS_LIST_GROUP_ADDRESSBOOK_ID_INT,/**< . */
+       CTS_LIST_GROUP_NAME_STR,/**< . */
+};
+
+/**
+ * Favorite List or Speeddial List
+ */
+enum SHORTCUTLIST{
+       CTS_LIST_SHORTCUT_ID_INT,/**< . */
+       CTS_LIST_SHORTCUT_CONTACT_ID_INT,/**< . */
+       CTS_LIST_SHORTCUT_FIRST_NAME_STR,/**< . */
+       CTS_LIST_SHORTCUT_LAST_NAME_STR,/**< . */
+       CTS_LIST_SHORTCUT_DISPLAY_NAME_STR,/**< . */
+       CTS_LIST_SHORTCUT_IMG_PATH_STR,/**< . */
+       CTS_LIST_SHORTCUT_NUMBER_STR,/**< only for #CTS_FAVOR_NUMBER */
+       CTS_LIST_SHORTCUT_NUMBER_TYPE_INT,/**< only for #CTS_FAVOR_NUMBER */
+       CTS_LIST_SHORTCUT_SPEEDDIAL_INT /**< only for #CTS_LIST_ALL_SPEEDDIAL */
+};
+
+
+/**
+ * SDN(Service Dialing Number) List
+ */
+enum SDNLIST{
+       CTS_LIST_SDN_NAME_STR,/**< . */
+       CTS_LIST_SDN_NUMBER_STR,/**< . */
+};
+
+/**
+ * Use for contacts_svc_get_list().
+ */
+typedef enum{
+       CTS_LIST_ALL_CONTACT, /**< #CONTACTLIST */
+       CTS_LIST_ALL_GROUP,/**< #GROUPLIST */
+       CTS_LIST_ALL_CUSTOM_NUM_TYPE,/**< #GROUPLIST */
+       CTS_LIST_ALL_CONTACT_FAVORITE,/**< #SHORTCUTLIST */
+       CTS_LIST_ALL_SPEEDDIAL,/**< #SHORTCUTLIST */
+       CTS_LIST_GROUPING_PLOG,/**< #PHONELOGLIST */
+       CTS_LIST_GROUPING_MSG_PLOG,/**< #PHONELOGLIST */
+       CTS_LIST_GROUPING_CALL_PLOG,/**< #PHONELOGLIST */
+       CTS_LIST_ALL_SDN,/**< #SDNLIST */
+       CTS_LIST_ALL_CONTACT_HAD_NUMBER,/**< #CONTACTLIST */
+       CTS_LIST_ALL_CONTACT_HAD_EMAIL,/**< #CONTACTLIST */
+       CTS_LIST_ALL_EMAIL_NUMBER,/**< #CONTACTLIST */
+       CTS_LIST_ALL_NUMBER_FAVORITE,/**< #SHORTCUTLIST */
+       CTS_LIST_OFTEN_USED_CONTACT, /**< #CONTACTLIST */
+       CTS_LIST_ALL_ADDRESSBOOK, /**< #ADDRESSBOOKLIST */
+       CTS_LIST_ALL_PLOG, /**< #PHONELOGLIST */
+       CTS_LIST_ALL_MISSED_CALL, /**< #PHONELOGLIST */
+       CTS_LIST_ALL_NUMBER, /**< #CONTACTLIST */
+}cts_get_list_op;
+/**
+ * This function gets iterator of the gotten data by op_code.
+ * \n Obtained iterator should be free using by contacts_svc_iter_remove().
+ *
+ * @param[in] op_code #cts_get_list_op
+ * @param[out] iter Point of data iterator
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @see contacts_svc_get_list_with_str(), contacts_svc_get_list_with_int()
+ * @par example
+ * @code
+ void get_contact_list(void)
+ {
+    CTSiter *iter = NULL;
+    contacts_svc_get_list(CTS_LIST_ALL_CONTACT, &iter);
+
+    while(CTS_SUCCESS == contacts_svc_iter_next(iter))
+    {
+       CTSvalue *contact = NULL;
+       char *first, *last, *display;
+       contacts_svc_iter_get_info(iter, &contact);
+
+       printf("(%8d)", contacts_svc_value_get_int(contact, CTS_LIST_CONTACT_ID_INT));
+       display = contacts_svc_value_get_str(contact, CTS_LIST_CONTACT_DISPLAY_STR);
+       if(display)
+          printf("%s :", display);
+       else
+       {
+          first = contacts_svc_value_get_str(contact, CTS_LIST_CONTACT_FIRST_STR);
+          last = contacts_svc_value_get_str(contact, CTS_LIST_CONTACT_LAST_STR);
+          if(CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+             printf("%s %s :", first, last);
+          else
+             printf("%s %s :", last, first);
+       }
+       printf("%s", contacts_svc_value_get_str(contact, CTS_LIST_CONTACT_IMG_PATH_STR));
+       printf("\n");
+       contacts_svc_value_free(contact);
+    }
+    contacts_svc_iter_remove(iter);
+ }
+ * @endcode
+ */
+int contacts_svc_get_list(cts_get_list_op op_code, CTSiter **iter);
+
+/**
+ * Use for contacts_svc_get_list_with_str().
+ */
+typedef enum{
+       CTS_LIST_PLOGS_OF_NUMBER,/**< #PHONELOGLIST */
+       CTS_LIST_CONTACTS_WITH_NAME,/**< #CONTACTLIST */
+       CTS_LIST_NUMBERINFOS_WITH_NAME,/**< #NUMBERLIST */
+       CTS_LIST_NUMBERINFOS_WITH_NUM,/**< #NUMBERLIST */
+       CTS_LIST_EMAILINFOS_WITH_EMAIL,/**< #EMAILLIST */
+       //CTS_LIST_NUMBERS_EMAILS_WITH_NAME,/**< #EMAILLIST */
+}cts_get_list_str_op;
+/**
+ * This function gets iterator of the gotten data by op_code with string search value.
+ * \n search_value is related with op_code. The Word after preposition is a property of search_value.
+ * \n Obtained iterator should be free using by contacts_svc_iter_remove().
+ *
+ * @param[in] op_code #cts_get_list_str_op
+ * @param[in] search_value String search value
+ * @param[out] iter Point of data iterator to be got
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @see contacts_svc_get_list(), contacts_svc_get_list_with_int()
+ */
+int contacts_svc_get_list_with_str(cts_get_list_str_op op_code, const char *search_value, CTSiter **iter);
+
+/**
+ * Use for contacts_svc_get_list_with_int().
+ */
+typedef enum{
+       CTS_LIST_MEMBERS_OF_GROUP_ID,/**< #CONTACTLIST */
+       CTS_LIST_MEMBERS_OF_ADDRESSBOOK_ID,/**< #CONTACTLIST */
+       CTS_LIST_NO_GROUP_MEMBERS_OF_ADDRESSBOOK_ID, /**< #CONTACTLIST */
+       CTS_LIST_GROUPS_OF_ADDRESSBOOK_ID, /**< #GROUPLIST */
+       CTS_LIST_ADDRESSBOOKS_OF_ACCOUNT_ID, /**< #ADDRESSBOOKLIST */
+       //CTS_LIST_EMAILS_OF_CONTACT_ID,/**< only use #CTS_LIST_EMAIL_CONTACT_ID_INT, #CTS_LIST_EMAIL_ADDR_STR */
+       //CTS_LIST_NUMBERS_OF_CONTACT_ID,/**< only use #CTS_LIST_NUM_CONTACT_ID_INT, #CTS_LIST_NUM_NUMBER_STR */
+}cts_get_list_int_op;
+/**
+ * This function gets iterator of the gotten data by op_code with integer search value.
+ * \n search_value is related with op_code. The Word after preposition is a property of search_value.
+ * \n Obtained iterator should be free using by contacts_svc_iter_remove().
+ *
+ * @param[in] op_code #cts_get_list_int_op
+ * @param[in] search_value Integer search value
+ * @param[out] iter Point of data iterator to be got
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @see contacts_svc_get_list(), contacts_svc_get_list_with_str()
+ */
+int contacts_svc_get_list_with_int(cts_get_list_int_op op_code, unsigned int search_value, CTSiter **iter);
+
+/**
+ * This function gets iterator of the gotten data related to updated contacts since the version(not include version).
+ * If contact includes both insert and update changes after version, the change type of contact is #CTS_OPERATION_INSERTED.
+ * If you want to get the last contacts version, use transaction explicitly.
+ * contacts_svc_end_trans() return the last contacts version.
+ * Obtained iterator should be free using by contacts_svc_iter_remove().
+ *
+ * @param[in] addressbook_id The index of addressbook. 0 is local(phone internal)
+ * @param[in] version The contact version gotten by contacts_svc_end_trans().
+ * @param[out] iter Point of data iterator to be got(#CHANGELIST)
+ * @return #CTS_SUCCESS on success, #CTS_ERR_DB_RECORD_NOT_FOUND on No change, Other negative value(#cts_error) on error,
+ *
+ * @see #CHANGELIST
+ * @par example
+ * @code
+  void sync_data(void)
+  {
+     int ret, version=0, index_num;
+     CTSiter *iter = NULL;
+     contacts_svc_get_updated_contacts(0, version, &iter);
+
+     while(CTS_SUCCESS == contacts_svc_iter_next(iter))
+     {
+        CTSstruct *contact= NULL;
+        CTSvalue *row_info = NULL;
+        row_info = contacts_svc_iter_get_info(iter);
+
+        index_num = contacts_svc_value_get_int(row_info, CTS_LIST_CHANGE_ID_INT);
+        printf("(%8d)\n", index_num);
+        int type = contacts_svc_value_get_int(row_info, CTS_LIST_CHANGE_TYPE_INT);
+        int ver = contacts_svc_value_get_int(row_info, CTS_LIST_CHANGE_TIME_INT);
+
+        if(CTS_OPERATION_UPDATED == type || CTS_OPERATION_INSERTED == type) {
+           contacts_svc_get_contact(index_num, &contact);
+           void *vcard_stream;
+           char file[128];
+           snprintf(file, sizeof(file), "test%d.vcf", index_num);
+           ret = contacts_svc_get_vcard_from_contact(contact, &vcard_stream);
+           if(CTS_SUCCESS == ret) {
+              //int fd = open(file, O_RDWR | O_CREAT);
+              //write(fd, (char *)vcard_stream, strlen((char *)vcard_stream));
+              //close(fd);
+              CTSstruct *new_contact = NULL;
+              ret = contacts_svc_get_contact_from_vcard(vcard_stream, &new_contact);
+              if(CTS_SUCCESS == ret) {
+                 get_contact(new_contact);
+                 contacts_svc_struct_free(new_contact);
+              }
+              free(vcard_stream);
+           }
+           if(CTS_OPERATION_INSERTED == type)
+              printf("Added : %d \n", ver);
+           else
+              printf("Updated : %d \n", ver);
+           contacts_svc_struct_free(contact);
+        }
+        else
+           printf("Deleted : %d \n", ver);
+
+        contacts_svc_value_free(row_info);
+     }
+     contacts_svc_iter_remove(iter);
+  }
+ * @endcode
+ */
+int contacts_svc_get_updated_contacts(int addressbook_id,
+      int version, CTSiter **iter);
+
+/**
+ * This function reads information from the iterator.
+ * Obtained information should be free using by contacts_svc_value_free().
+ *
+ * @param[in] iter The data iterator
+ * @return The gotten information, or NULL if no value is obtained or error
+ */
+CTSvalue* contacts_svc_iter_get_info(CTSiter *iter);
+
+/**
+ * This function removes the iterator.
+ * \n You should call this function after using iterator.
+ *
+ * @param[in] iter The data iterator
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_iter_remove(CTSiter *iter);
+
+/**
+ * This function moves the iterator to the next record, if any.
+ * Must also be called before reading first record, to determine
+ * whether there is such a record at all.
+ * If there's no next record, returns #CTS_ERR_FINISH_ITER.
+ *
+ * @param[in] iter The data iterator
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_iter_next(CTSiter *iter);
+
+/**
+ * This is the signature of a callback function added with contacts_svc_list_foreach(),
+ * contacts_svc_list_with_int_foreach() and contacts_svc_list_with_str_foreach().
+ * \n This function is invoked in the above functions.
+ * \n If this function doesn't return #CTS_SUCCESS, foreach function is terminated.
+ *
+ * @param[in] value data of a record.
+ * @param[in] user_data The data which is set by contacts_svc_list_foreach(),
+ * contacts_svc_list_with_int_foreach() and contacts_svc_list_with_str_foreach().
+ * @return #CTS_SUCCESS on success, other value on error
+ */
+typedef int (*cts_foreach_fn)(CTSvalue *value, void *user_data);
+
+
+/**
+ * This function calls #cts_foreach_fn for each record of list gotten by op_code.
+ *
+ * @param[in] op_code #cts_get_list_op
+ * @param[in] cb callback function pointer(#cts_foreach_fn)
+ * @param[in] user_data data which is passed to callback function
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @see contacts_svc_get_list()
+ */
+int contacts_svc_list_foreach(cts_get_list_op op_code,
+   cts_foreach_fn cb, void *user_data);
+
+/**
+ * This function calls #cts_foreach_fn for each record of list gotten by op_code.
+ *
+ * @param[in] op_code #cts_get_list_int_op
+ * @param[in] search_value Integer search value
+ * @param[in] cb callback function pointer(#cts_foreach_fn)
+ * @param[in] user_data data which is passed to callback function
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @see contacts_svc_get_list_with_int()
+ */
+int contacts_svc_list_with_int_foreach(cts_get_list_int_op op_code,
+   unsigned int search_value, cts_foreach_fn cb, void *user_data);
+
+/**
+ * This function calls #cts_foreach_fn for each record of list gotten by op_code.
+ *
+ * @param[in] op_code #cts_get_list_str_op
+ * @param[in] search_value String search value
+ * @param[in] cb callback function pointer(#cts_foreach_fn)
+ * @param[in] data data which is passed to callback function
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @see contacts_svc_get_list_with_str()
+ */
+int contacts_svc_list_with_str_foreach(cts_get_list_str_op op_code,
+   const char *search_value, cts_foreach_fn cb, void *data);
+
+/**
+ * Use for contacts_svc_list_str_filter_new().
+ */
+typedef enum {
+       CTS_FILTERED_PLOGS_OF_NUMBER = CTS_LIST_PLOGS_OF_NUMBER,/**< #PHONELOGLIST */
+       CTS_FILTERED_CONTACTS_WITH_NAME = CTS_LIST_CONTACTS_WITH_NAME,/**< #CONTACTLIST */
+       CTS_FILTERED_NUMBERINFOS_WITH_NAME = CTS_LIST_NUMBERINFOS_WITH_NAME,/**< #NUMBERLIST */
+       CTS_FILTERED_NUMBERINFOS_WITH_NUM = CTS_LIST_NUMBERINFOS_WITH_NUM,/**< #NUMBERLIST */
+       CTS_FILTERED_EMAILINFOS_WITH_EMAIL= CTS_LIST_EMAILINFOS_WITH_EMAIL,/**< #EMAILLIST */
+}cts_str_filter_op;
+
+/**
+ * Use for contacts_svc_list_filter_new().
+ */
+typedef enum {
+       CTS_FILTERED_ALL_CONTACT,/**< #CONTACTLIST */
+}cts_filter_op;
+
+/**
+ * Use for contacts_svc_list_filter_new(), contacts_svc_list_str_filter_new().
+ */
+typedef enum {
+       CTS_LIST_FILTER_NONE, /**< . */
+       CTS_LIST_FILTER_ADDRESBOOK_ID_INT, /**< exclusive with #CTS_LIST_FILTER_GROUP_ID_INT */
+       CTS_LIST_FILTER_GROUP_ID_INT, /**< exclusive with #CTS_LIST_FILTER_ADDRESBOOK_ID_INT */
+       CTS_LIST_FILTER_LIMIT_INT, /**< . */
+       CTS_LIST_FILTER_OFFSET_INT, /**< Offset depends on Limit(#CTS_LIST_FILTER_LIMIT_INT) */
+}cts_filter_type;
+
+/**
+ * Allocate, initialize and return a new contacts service list filter with constraints.
+ * The constaint is composed with the pair of (type, val).
+ * The constaints list should be terminated with #CTS_LIST_FILTER_NONE,
+ * therefore the count of parameter is an odd number.
+ * This should be used for getting filtered list only,
+ * if not, be sure to use contacts_svc_get_list_with_str().
+ *
+ * @param[in] list_type type of list(#cts_str_filter_op)
+ * @param[in] search_value String search value
+ * @param[in] first_type type of first constraint
+ * @return The pointer of New contacts service list filter, NULL on error
+ * @see contacts_svc_list_filter_free()
+ */
+CTSfilter* contacts_svc_list_str_filter_new(cts_str_filter_op list_type,
+   const char *search_value, cts_filter_type first_type, ...);
+
+/**
+ * Allocate, initialize and return a new contacts service list filter with constraints.
+ * The constaint is composed with the pair of (type, val).
+ * The constaints list should be terminated with #CTS_LIST_FILTER_NONE,
+ * therefore the count of parameter is an even number.
+ * This should be used for getting filtered list only,
+ * if not, be sure to use contacts_svc_get_list().
+ *
+ * @param[in] list_type type of list(#cts_filter_op)
+ * @param[in] first_type type of first constraint
+ * @return The pointer of New contacts service list filter, NULL on error
+ * @see contacts_svc_list_filter_free()
+ */
+CTSfilter* contacts_svc_list_filter_new(cts_filter_op list_type, cts_filter_type first_type, ...);
+
+/**
+ * A destructor for contacts service list filter.
+ *
+ * @param[in] filter A contacts service struct
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @see contacts_svc_list_filter_new(), contacts_svc_list_str_filter_new()
+ */
+int contacts_svc_list_filter_free(CTSfilter *filter);
+
+/**
+ * This function calls cb(#cts_foreach_fn) for each record of list gotten by filter.
+ *
+ * @param[in] filter The filter for searching
+ * @param[in] cb callback function pointer(#cts_foreach_fn)
+ * @param[in] user_data data which is passed to callback function
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_list_with_filter_foreach(CTSfilter *filter,
+   cts_foreach_fn cb, void *user_data);
+
+/**
+ * It is the smartsearch exclusive function. It is supported for only smartsearch.
+ * It can be changed without announcement.
+ * This function calls #cts_foreach_fn for each record of list.
+ *
+ * @param[in] search_str String search value(number or name)
+ * @param[in] limit an upper bound on the number of result. If it has a negative value, there is no upper bound.
+ * @param[in] offset It omits offset rows for the result.
+ * @param[in] cb callback function pointer(#cts_foreach_fn) with #CTSvalue(#NUMBERLIST)
+ * @param[in] user_data data which is passed to callback function
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_smartsearch_excl(const char *search_str, int limit, int offset,
+   cts_foreach_fn cb, void *user_data);
+
+/**
+ * @}
+ */
+//-->
+
+
+#endif //__CTS_LIST_H__
+
diff --git a/src/cts-normalize.c b/src/cts-normalize.c
new file mode 100755 (executable)
index 0000000..cd003ef
--- /dev/null
@@ -0,0 +1,615 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *          Donghee Ye <donghee.ye@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <string.h>
+
+#include "cts-internal.h"
+#include "cts-normalize.h"
+#include "cts-socket.h"
+#include "cts-pthread.h"
+#include "cts-utils.h"
+
+static int (*extra_normalize_fn)(char dest[][CTS_SQL_MAX_LEN]);
+
+static inline int check_utf8(char c)
+{
+       if (c < 128)
+               return 1;
+       else if ((c & (char)0xe0) == (char)0xc0)
+               return 2;
+       else if ((c & (char)0xf0) == (char)0xe0)
+               return 3;
+       else if ((c & (char)0xf8) == (char)0xf0)
+               return 4;
+       else if ((c & (char)0xfc) == (char)0xf8)
+               return 5;
+       else if ((c & (char)0xfe) == (char)0xfc)
+               return 6;
+       else
+               return CTS_ERR_FAIL;
+}
+
+static inline bool check_dirty_number(char digit)
+{
+       switch (digit)
+       {
+       case '0' ... '9':
+       case 'p':
+       case 'w':
+       case 'P':
+       case 'W':
+               return false;
+       case '+': //only first position
+       default:
+               return true;
+       }
+}
+
+int cts_clean_number(const char *src, char *dest, int dest_size)
+{
+       int s_pos=0, d_pos=0, char_type;
+
+       if (NULL == src)
+               ERR("The parameter(src) is NULL");
+       else
+       {
+               if ('+' == src[s_pos])
+                       dest[d_pos++] = src[s_pos++];
+
+               while (src[s_pos] != 0)
+               {
+                       if (d_pos >= dest_size-2) break;
+                       char_type = check_utf8(src[s_pos]);
+                       if (char_type <= 1) {
+                               if (check_dirty_number(src[s_pos])) {
+                                       s_pos++;
+                                       continue;
+                               }
+                               dest[d_pos++] = src[s_pos++];
+                       }
+                       else
+                               s_pos += char_type;
+               }
+       }
+
+       dest[d_pos] = 0;
+       return d_pos;
+}
+
+static int cts_remove_special_char(const char *src, char *dest, int dest_size)
+{
+       int s_pos=0, d_pos=0, char_type, src_size;
+
+       if (NULL == src) {
+               ERR("The parameter(src) is NULL");
+               dest[d_pos] = '\0';
+               return 0;
+       }
+       src_size = strlen(src);
+
+       while (src[s_pos] != 0)
+       {
+               char_type = check_utf8(src[s_pos]);
+
+               if (0 < char_type && char_type < dest_size - d_pos && char_type <= src_size - s_pos) {
+                       memcpy(dest+d_pos, src+s_pos, char_type);
+                       d_pos += char_type;
+                       s_pos += char_type;
+               }
+               else {
+                       ERR("The parameter(src:%s) has invalid character set", src);
+                       dest[d_pos] = '\0';
+                       return CTS_ERR_ARG_INVALID;
+               }
+       }
+
+       dest[d_pos] = '\0';
+       return d_pos;
+}
+
+int cts_normalize_str(const char *src, char *dest, int dest_size)
+{
+       int ret;
+       ret = cts_remove_special_char(src, dest, dest_size);
+       retvm_if(ret < CTS_SUCCESS, ret, "cts_remove_special_char() Failed(%d)", ret);
+       ret = CTS_SUCCESS;
+
+       cts_mutex_lock(CTS_MUTEX_SOCKET_FD);
+       ret = cts_request_normalize_str(dest, dest, dest_size);
+       cts_mutex_unlock(CTS_MUTEX_SOCKET_FD);
+
+       return ret;
+}
+
+void cts_set_extra_normalize_fn(int (*fn)(char dest[][CTS_SQL_MAX_LEN]))
+{
+       extra_normalize_fn = fn;
+}
+
+int cts_normalize_name(cts_name *src,
+               char dest[][CTS_SQL_MAX_LEN], bool is_display)
+{
+       int ret;
+       if (is_display) {
+               ret = cts_remove_special_char(src->display, dest[CTS_NN_FIRST],
+                               sizeof(dest[CTS_NN_FIRST]));
+               warn_if(ret < CTS_SUCCESS, "cts_remove_special_char() Failed(%d)", ret);
+               snprintf(dest[CTS_NN_SORTKEY], sizeof(dest[CTS_NN_SORTKEY]), "%s", dest[CTS_NN_FIRST]);
+               ret = CTS_SUCCESS;
+       }
+       else {
+               ret = cts_remove_special_char(src->first, dest[CTS_NN_FIRST],
+                               sizeof(dest[CTS_NN_FIRST]));
+               warn_if(ret < CTS_SUCCESS, "cts_remove_special_char() Failed(%d)", ret);
+               ret = CTS_SUCCESS;
+
+               ret = cts_remove_special_char(src->last, dest[CTS_NN_LAST],
+                               sizeof(dest[CTS_NN_LAST]));
+               warn_if(ret < CTS_SUCCESS, "cts_remove_special_char() Failed(%d)", ret);
+               ret = CTS_SUCCESS;
+
+               if (!*dest[CTS_NN_LAST])
+                       snprintf(dest[CTS_NN_SORTKEY], sizeof(dest[CTS_NN_SORTKEY]), "%s", dest[CTS_NN_FIRST]);
+               else if (!*dest[CTS_NN_FIRST])
+                       snprintf(dest[CTS_NN_SORTKEY], sizeof(dest[CTS_NN_SORTKEY]), "%s", dest[CTS_NN_LAST]);
+               else if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       snprintf(dest[CTS_NN_SORTKEY], sizeof(dest[CTS_NN_SORTKEY]), "%s %s", dest[CTS_NN_FIRST], dest[CTS_NN_LAST]);
+               else
+                       snprintf(dest[CTS_NN_SORTKEY], sizeof(dest[CTS_NN_SORTKEY]), "%s, %s", dest[CTS_NN_LAST], dest[CTS_NN_FIRST]);
+       }
+
+       if (extra_normalize_fn)
+               ret = extra_normalize_fn(dest);
+       else {
+               cts_mutex_lock(CTS_MUTEX_SOCKET_FD);
+               ret = cts_request_normalize_name(dest);
+               cts_mutex_unlock(CTS_MUTEX_SOCKET_FD);
+       }
+
+       return ret;
+}
+
+/**
+ * This function make searchable string.
+ * The string can use at contacts_svc_normalized_strstr().
+ *
+ * @param[in] src the string to convert
+ * @param[out] dest The pointer to get normalized string.
+ * @param[out] dest_len the size of dest.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+       char normalized_str[512];
+       const char *name = "Test"
+
+       ret = contacts_svc_normalize_str(name, normalized_str, sizeof(normalized_str));
+
+       if(CTS_SUCCESS != ret)
+               printf("Error : contacts_svc_normalize_str() Failed(%d)", ret);
+       else
+               printf("original string is %s, normalized string is %s", name, normalized_str);
+ * @endcode
+ */
+API int contacts_svc_normalize_str(const char *src, char *dest, const int dest_len)
+{
+       int ret;
+       retv_if(NULL == dest, CTS_ERR_ARG_NULL);
+       retvm_if(dest_len <= 0, CTS_ERR_ARG_INVALID, "dest_len(%d) is Invalid", dest_len);
+
+       ret = cts_normalize_str(src, dest, dest_len);
+       retvm_if(ret < CTS_SUCCESS, ret, "cts_normalize_str() Failed(%d)", ret);
+
+       return CTS_SUCCESS;
+}
+
+static inline bool is_choseong(const char *src)
+{
+       unsigned short tmp;
+
+       tmp = (src[1] << 8) | src[2];
+       if (((char)0xE1 == src[0] && CTS_COMPARE_BETWEEN(0x8480, tmp, 0x859F)) /* korean -Hangul Jamo*/
+                       || ((char)0xEA == src[0] && CTS_COMPARE_BETWEEN(0xA5A0, tmp, 0xA5BC))) /* korean -Hangul Jamo extended A*/
+       {
+               return true;
+       }
+       return false;
+}
+
+static inline bool is_jungseong(const char *src)
+{
+       unsigned short tmp;
+
+       tmp = (src[1] << 8) | src[2];
+       if (((char)0xE1 == src[0] && CTS_COMPARE_BETWEEN(0x85A0, tmp, 0x86A7))/* korean -Hangul Jamo*/
+                       || ((char)0xED == src[0] && CTS_COMPARE_BETWEEN(0x9EB0, tmp, 0x9F86)))/* korean -Hangul Jamo extended B */
+       {
+               return true;
+       }
+       return false;
+}
+
+static inline bool is_diacritical(const char *src)
+{
+       unsigned short tmp;
+
+       if (!src || !*src || !*(src+1))
+               return false;
+
+       tmp = (src[0] << 8) | src[1];
+       if (CTS_COMPARE_BETWEEN(0xCC80, tmp, 0xCCBF)
+                       || CTS_COMPARE_BETWEEN(0xCD80, tmp, 0xCDAF))
+       {
+               return true;
+       }
+       return false;
+}
+
+static inline bool compare_unicode(const char *str1, const char *str2, int str2_len)
+{
+       int k;
+       for (k=0; k<str2_len;k++)
+               if (!str1[k] || !str2[k] || str1[k] != str2[k])
+                       return false;
+       return true;
+}
+
+/**
+ * This function compares compares two strings which must have been normalized already.
+ * If search_str is included in str, this function return #CTS_SUCCESS. \n
+ * The behavior of this function cannot fix because of localization.
+ * So, The behavior can be different from each other.
+ *
+ * @param[in] haystack Base string.
+ * @param[in] needle searching string
+ * @param[out] len substring length
+ * @return a position of the beginning of the substring, Negative value(#cts_error) on error or difference.
+ * @par example
+ * @code
+       ret = contacts_svc_compare_normalized_str(str1, str2, &len);
+       if(CTS_SUCCESS == ret) {
+               snprintf(first, ret+1, "%s", item_data->display);
+               snprintf(middle, len+1, "%s", item_data->display + ret);
+               printf("%s -> %s, %s, %s", item_data->display, first, middle, item_data->display + ret + len);
+       } else
+               printf("str1 doesn't has str2");
+ * @endcode
+ */
+API int contacts_svc_normalized_strstr(const char *haystack,
+               const char *needle, int *len)
+{
+       int i, j, wind, h_len, n_len;
+       int first_needle_len;
+       int equal_index;
+       int equal_length;
+       int equal_wind = 0;
+       bool counted = false;
+       retvm_if(NULL == haystack, -1, "The parameter(haystack) is NULL");
+       retvm_if(NULL == needle, -1, "The parameter(needle) is NULL");
+       CTS_DBG("haystack = %s, needle = %s", haystack, needle);
+
+       h_len = 1;
+       n_len = 1;
+       equal_index = 0;
+       first_needle_len = check_utf8(needle[0]);
+       for (i=0, j=0;i<strlen(haystack);i = wind?wind:(i+h_len)) {
+               if (equal_wind) {
+                       equal_index = equal_wind;
+                       counted = false;
+               }
+               wind = 0;
+               equal_length = 0;
+               equal_wind = 0;
+               for (j=0;j<strlen(needle);) {
+                       bool equal;
+                       h_len = check_utf8(haystack[i]);
+
+                       if (h_len == 1 && haystack[i] == 0x1) {         //skip seperator
+                               counted = false;
+                               i+=h_len;
+                               continue;
+                       }
+
+                       n_len = check_utf8(needle[j]);
+                       if (n_len == 1 && needle[j] == 0x1) {           //skip seperator
+                               j++;
+                               continue;
+                       }
+
+                       if (wind == 0 && j && 0 < i) {
+                               if (h_len == first_needle_len && compare_unicode(&haystack[i], needle, first_needle_len)
+                                               && !is_diacritical(&haystack[i])) {
+                                       unsigned short tmp;
+
+                                       tmp = (haystack[i+1] << 8) | haystack[i+2];
+                                       if (!counted) {
+                                               wind = i;
+                                               equal_wind = equal_index + equal_length;
+                                       }
+                               }
+                       }
+
+                       if ((2 == h_len && is_diacritical(&haystack[i]))
+                                       && (2 != n_len || !is_diacritical(&needle[j]))) {
+                               if (j == 0) {
+                                       if (counted)
+                                               equal_index++;
+                                       else {
+                                               equal_index += h_len;
+                                               counted = true;
+                                       }
+                               }
+                               else if (!counted) {
+                                       equal_length += h_len;
+                                       counted = true;
+                               }
+                               else if (counted)
+                                       equal_length++;
+                               i+=h_len;
+                               continue;
+                       }
+
+                       if (h_len != n_len) {
+                               if (!counted) {
+                                       equal_index += (equal_length + h_len);
+                                       counted = true;
+                               }
+                               break;
+                       }
+
+                       if (3 == n_len && is_choseong(&needle[j]) && !(is_choseong(&haystack[i]))) {
+                               if (j < (n_len+1) || !is_choseong(&needle[j-n_len-1])) {                // skip 강나 search by 가나
+                                       if (!counted) {
+                                               equal_index += (equal_length + h_len);
+                                               counted = true;
+                                       }
+                                       break;
+                               }
+                               else {
+                                       if (j == 0) {
+                                               if (!counted) {
+                                                       equal_index += h_len;
+                                                       counted = true;
+                                               }
+                                       }
+                                       else if (!counted) {
+                                               equal_length += h_len;
+                                               counted = true;
+                                       }
+                                       i+=h_len;
+                                       continue;
+                               }
+                       }
+
+                       equal = compare_unicode(&haystack[i], &needle[j], n_len);
+
+                       if (equal) {
+                               if (!counted) {
+                                       equal_length += h_len;
+                                       counted = true;
+                               }
+                               else if (2 == n_len && is_diacritical(&needle[j]))
+                                       equal_length ++;
+                               j += n_len;
+                               i+=h_len;
+                               continue;
+                       }
+                       else {
+                               if (!counted) {
+                                       equal_index += (equal_length + h_len);
+                                       counted = true;
+                               }
+                               else {
+                                       if (2 == n_len && is_diacritical(&needle[j]))
+                                               equal_index += (equal_length + 1);
+                                       else
+                                               equal_index += equal_length;
+                               }
+                               break;
+                       }
+               }
+
+               if ('\0' == needle[j]) {
+                       if ('\0' != haystack[i]) {
+                               h_len = check_utf8(haystack[i]);
+                               if(h_len == 2 && is_diacritical(&haystack[i]))
+                                       equal_length++;
+                       }
+                       *len = equal_length;
+                       return equal_index;
+               }
+       }
+
+       CTS_DBG("NOT match");
+       return -1;
+}
+
+static inline const char* cts_clean_country_code(const char *src)
+{
+       int ret = 1;
+       switch (src[ret++]-'0')
+       {
+       case 1:
+       case 7:
+               break;
+       case 2:
+               switch (src[ret++]-'0')
+               {
+               case 0:
+               case 7:
+                       break;
+               case 1:
+               case 2:
+               case 3:
+               case 4:
+               case 5:
+               case 6:
+               case 8:
+               case 9:
+                       ret += 1;
+                       break;
+               default:
+                       ERR("The parameter(src:%s) has invalid character set", src);
+               }
+               break;
+       case 3:
+               switch (src[ret++]-'0')
+               {
+               case 0:
+               case 1:
+               case 2:
+               case 3:
+               case 4:
+               case 6:
+               case 9:
+                       break;
+               case 5:
+               case 7:
+               case 8:
+                       ret += 1;
+                       break;
+               default:
+                       ERR("The parameter(src:%s) has invalid character set", src);
+               }
+               break;
+       case 4:
+               switch (src[ret++]-'0')
+               {
+               case 0:
+               case 1:
+               case 3:
+               case 4:
+               case 5:
+               case 6:
+               case 7:
+               case 8:
+               case 9:
+                       break;
+               case 2:
+                       ret += 1;
+                       break;
+               default:
+                       ERR("The parameter(src:%s) has invalid character set", src);
+               }
+               break;
+       case 5:
+               switch (src[ret++]-'0')
+               {
+               case 1:
+               case 2:
+               case 3:
+               case 4:
+               case 5:
+               case 6:
+               case 7:
+               case 8:
+                       break;
+               case 0:
+               case 9:
+                       ret += 1;
+                       break;
+               default:
+                       ERR("The parameter(src:%s) has invalid character set", src);
+               }
+               break;
+       case 6:
+               switch (src[ret++]-'0')
+               {
+               case 0:
+               case 1:
+               case 2:
+               case 3:
+               case 4:
+               case 5:
+               case 6:
+                       break;
+               case 7:
+               case 8:
+               case 9:
+                       ret += 1;
+                       break;
+               default:
+                       ERR("The parameter(src:%s) has invalid character set", src);
+               }
+               break;
+       case 8:
+               switch (src[ret++]-'0')
+               {
+               case 1:
+               case 2:
+               case 4:
+               case 6:
+                       break;
+               case 0:
+               case 3:
+               case 5:
+               case 7:
+               case 8:
+               case 9:
+                       ret += 1;
+                       break;
+               default:
+                       ERR("The parameter(src:%s) has invalid character set", src);
+               }
+               break;
+       case 9:
+               switch (src[ret++]-'0')
+               {
+               case 0:
+               case 1:
+               case 2:
+               case 3:
+               case 4:
+               case 5:
+               case 8:
+                       break;
+               case 6:
+               case 7:
+               case 9:
+                       ret += 1;
+                       break;
+               default:
+                       ERR("The parameter(src:%s) has invalid character set", src);
+               }
+               break;
+       case 0:
+       default:
+               ERR("The parameter(src:%s) has invalid character set", src);
+               return src;
+       }
+
+       return &src[ret];
+}
+
+const char* cts_normalize_number(const char *src)
+{
+       const char *normalized_number;
+
+       if ('+' == src[0])
+               normalized_number = cts_clean_country_code(src);
+       else if ('0' == src[0])
+               normalized_number = src+1;
+       else
+               normalized_number = src;
+
+       CTS_DBG("src = %s, normalized = %s", src, normalized_number);
+
+       return normalized_number;
+}
diff --git a/src/cts-normalize.h b/src/cts-normalize.h
new file mode 100755 (executable)
index 0000000..644e9a1
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *          Donghee Ye <donghee.ye@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_NORMALIZE_H__
+#define __CTS_NORMALIZE_H__
+
+#include "cts-sqlite.h"
+
+#define CTS_COMPARE_BETWEEN(left_range, value, right_range) (((left_range) <= (value)) && ((value) <= (right_range)))
+#define CTS_VCONF_DEFAULT_LANGUAGE "db/service/contacts/default_lang"
+
+/**
+ * Language Type
+ */
+enum LANGTYPE{
+       CTS_LANG_NUMBER = 0,
+       CTS_LANG_DEFAULT = 1,
+       CTS_LANG_SYMBOL = 2,
+       CTS_LANG_ENGLISH = 3,
+       CTS_LANG_KOREAN = 4, /* always last-first */
+       CTS_LANG_CHINESE = 5,
+       CTS_LANG_JAPANESE = 6,
+       CTS_LANG_FRENCH = 7,
+       CTS_LANG_GERMAN = 8,
+       CTS_LANG_ITALIAN = 9,
+       CTS_LANG_RUSSIAN = 10,
+       CTS_LANG_DUTCH = 11,
+       CTS_LANG_PORTUGUESE = 12,
+       CTS_LANG_TURKISH = 13,
+       CTS_LANG_GREEK = 14,
+       CTS_LANG_SPANISH = 15,
+       CTS_LANG_OTHERS = 16,
+};
+
+enum{
+       CTS_NN_FIRST,
+       CTS_NN_LAST,
+       CTS_NN_SORTKEY,
+       CTS_NN_MAX,
+};
+
+int cts_normalize_str(const char *src, char *dest, int dest_size);
+int cts_normalize_name(cts_name *src, char dest[][CTS_SQL_MAX_LEN], bool is_display);
+void cts_set_extra_normalize_fn(int (*fn)(char dest[][CTS_SQL_MAX_LEN]));
+const char* cts_normalize_number(const char *src);
+int cts_clean_number(const char *src, char *dest, int dest_size);
+
+#endif //__CTS_NORMALIZE_H__
diff --git a/src/cts-phonelog.c b/src/cts-phonelog.c
new file mode 100755 (executable)
index 0000000..003c1ef
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "cts-internal.h"
+#include "cts-schema.h"
+#include "cts-sqlite.h"
+#include "cts-contact.h"
+#include "cts-utils.h"
+#include "cts-types.h"
+#include "cts-normalize.h"
+#include "cts-phonelog.h"
+
+#define CTS_NAME_LEN_MAX 128
+
+static int cts_phonelog_accumulation_handle(cts_plog *plog)
+{
+       int ret, cnt, duration, total_cnt, total_duration, deal_cnt=0;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       snprintf(query, sizeof(query), "SELECT * FROM %s WHERE id <= 2",
+                       CTS_TABLE_PHONELOG_ACC);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       while (CTS_TRUE == cts_stmt_step(stmt))
+       {
+               ret = cts_stmt_get_int(stmt, 0);
+               if (1 == ret) {
+                       cnt = cts_stmt_get_int(stmt, 1);
+                       duration = cts_stmt_get_int(stmt, 3);
+                       deal_cnt++;
+               }else if (2 == ret) {
+                       total_cnt = cts_stmt_get_int(stmt, 1);
+                       total_duration = cts_stmt_get_int(stmt, 3);
+                       deal_cnt++;
+               }
+       }
+       cts_stmt_finalize(stmt);
+
+       if (deal_cnt != 2) {
+               ERR("Getting plog accumulation data is Failed");
+               return CTS_ERR_DB_FAILED;
+       }
+
+       snprintf(query, sizeof(query), "INSERT OR REPLACE INTO %s VALUES(?, ?, NULL, ?)",
+                       CTS_TABLE_PHONELOG_ACC);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       cts_stmt_bind_int(stmt, 1, 1);
+       cts_stmt_bind_int(stmt, 2, cnt+1);
+       cts_stmt_bind_int(stmt, 3, duration + plog->extra_data1);
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return ret;
+       }
+       cts_stmt_reset(stmt);
+
+       cts_stmt_bind_int(stmt, 1, 2);
+       cts_stmt_bind_int(stmt, 2, total_cnt+1);
+       cts_stmt_bind_int(stmt, 3, total_duration + plog->extra_data1);
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return ret;
+       }
+
+       cts_stmt_finalize(stmt);
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_insert_phonelog(cts_plog *plog)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char clean_num[CTS_NUMBER_MAX_LEN], query[CTS_SQL_MAX_LEN] = {0};
+       const char *normal_num;
+
+       retvm_if(plog->log_type <= CTS_PLOG_TYPE_NONE
+                       || CTS_PLOG_TYPE_MAX <= plog->log_type,
+                       CTS_ERR_ARG_INVALID, "phonelog type(%d) is invaid", plog->log_type);
+
+       cts_clean_number(plog->number, clean_num, sizeof(clean_num));
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       snprintf(query, sizeof(query), "INSERT INTO %s("
+                       "number, normal_num, related_id, log_type, log_time, data1, data2) "
+                       "VALUES(?, ?, ?, %d, %d, %d, ?)",
+                       CTS_TABLE_PHONELOGS, plog->log_type,
+                       plog->log_time, plog->extra_data1);
+
+       stmt = cts_query_prepare(query);
+       if (NULL == stmt) {
+               ERR("cts_query_prepare() Failed");
+               contacts_svc_end_trans(false);
+               return CTS_ERR_DB_FAILED;
+       }
+
+       if (*clean_num) {
+               cts_stmt_bind_text(stmt, 1, clean_num);
+               normal_num = cts_normalize_number(clean_num);
+               cts_stmt_bind_text(stmt, 2, normal_num);
+       }
+
+       if (0 < plog->related_id)
+               cts_stmt_bind_int(stmt, 3, plog->related_id);
+
+       if (plog->extra_data2)
+               cts_stmt_bind_text(stmt, 4, plog->extra_data2);
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       cts_stmt_finalize(stmt);
+
+       if (CTS_PLOG_TYPE_VOICE_OUTGOING == plog->log_type
+                       || CTS_PLOG_TYPE_VIDEO_OUTGOING == plog->log_type)
+       {
+               ret = cts_phonelog_accumulation_handle(plog);
+               if (CTS_SUCCESS != ret) {
+                       ERR("cts_phonelog_accumulation_handle() Failed");
+                       contacts_svc_end_trans(false);
+                       return ret;
+               }
+       }
+
+       if (CTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN == plog->log_type ||
+                       CTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN == plog->log_type)
+               cts_set_missed_call_noti();
+
+       cts_set_plog_noti();
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+//extra_data1 : duration, message_id
+//extra_data2 : short message
+API int contacts_svc_insert_phonelog(CTSvalue* phone_log)
+{
+       int ret;
+       cts_plog *plog = (cts_plog *)phone_log;
+
+       retv_if(NULL == phone_log, CTS_ERR_ARG_NULL);
+       retvm_if(plog->id, CTS_ERR_ARG_INVALID, "The phone_log has ID(%d)", plog->id);
+
+       ret = cts_insert_phonelog(plog);
+       retvm_if(CTS_SUCCESS != ret, ret,"cts_insert_phonelog() Failed(%d)", ret);
+
+       if (0 < plog->related_id) {
+               ret = cts_increase_outgoing_count(plog->related_id);
+               warn_if(CTS_SUCCESS != ret, "cts_increase_outgoing_count() Failed(%d)", ret);
+       }
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_delete_phonelog(cts_del_plog_op op_code, ...)
+{
+       int id, ret;
+       char *number;
+       char query[CTS_SQL_MAX_LEN];
+       va_list args;
+
+       switch (op_code)
+       {
+       case CTS_PLOG_DEL_BY_ID:
+               va_start(args, op_code);
+               id = va_arg(args, int);
+               va_end(args);
+               snprintf(query, sizeof(query), "DELETE FROM %s WHERE id = %d",
+                               CTS_TABLE_PHONELOGS, id);
+               break;
+       case CTS_PLOG_DEL_BY_NUMBER:
+               va_start(args, op_code);
+               number = va_arg(args, char *);
+               va_end(args);
+               retv_if(NULL == number, CTS_ERR_ARG_NULL);
+               snprintf(query, sizeof(query), "DELETE FROM %s WHERE number = '%s'",
+                               CTS_TABLE_PHONELOGS, number);
+               break;
+       case CTS_PLOG_DEL_BY_MSGID:
+               va_start(args, op_code);
+               id = va_arg(args, int);
+               va_end(args);
+               snprintf(query, sizeof(query), "DELETE FROM %s "
+                               "WHERE data1 = %d AND %d <= log_type AND log_type <= %d",
+                               CTS_TABLE_PHONELOGS,
+                               id, CTS_PLOG_TYPE_MMS_INCOMMING, CTS_PLOG_TYPE_MMS_BLOCKED);
+               break;
+       case CTS_PLOG_DEL_NO_NUMBER:
+               snprintf(query, sizeof(query), "DELETE FROM %s WHERE number ISNULL",
+                               CTS_TABLE_PHONELOGS);
+               break;
+       default:
+               ERR("Invalid op_code. Your op_code(%d) is not supported.", op_code);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       cts_set_plog_noti();
+       if (CTS_PLOG_DEL_BY_MSGID != op_code)
+               cts_set_missed_call_noti();
+
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_get_phonelog(int plog_id, CTSvalue **phonelog)
+{
+       int ret;
+       cts_stmt stmt;
+       cts_plog *plog;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       snprintf(query, sizeof(query),
+                       "SELECT id, number, related_id, log_type, log_time, data1, data2 "
+                       "FROM %s WHERE id = %d",
+                       CTS_TABLE_PHONELOGS, plog_id);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_DB_RECORD_NOT_FOUND;
+       }
+
+       plog = (cts_plog *)contacts_svc_value_new(CTS_VALUE_PHONELOG);
+       if (plog) {
+               ret = CTS_SUCCESS;
+               plog->v_type = CTS_VALUE_RDONLY_PLOG;
+               plog->id = cts_stmt_get_int(stmt, 0);
+               plog->number = SAFE_STRDUP(cts_stmt_get_text(stmt, 1));
+               plog->related_id = cts_stmt_get_int(stmt, 2);
+               plog->log_type = cts_stmt_get_int(stmt, 3);
+               plog->log_time = cts_stmt_get_int(stmt, 4);
+               plog->extra_data1 = cts_stmt_get_int(stmt, 5);
+               plog->extra_data2 = SAFE_STRDUP(cts_stmt_get_text(stmt, 6));
+
+               *phonelog = (CTSvalue*)plog;
+
+               cts_stmt_finalize(stmt);
+               return CTS_SUCCESS;
+       }
+       else {
+               ERR("contacts_svc_value_new() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_OUT_OF_MEMORY;
+       }
+}
+
+
+API int contacts_svc_phonelog_set_seen(int index, int type)
+{
+       int ret;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       retvm_if(CTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN != type &&
+                       CTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN != type &&
+                       CTS_PLOG_TYPE_NONE != type,
+                       CTS_ERR_ARG_INVALID,
+                       "The type is invalid. It must be CTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN"
+                       " or CTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN");
+
+       if (0 == index) {
+               if (CTS_PLOG_TYPE_NONE == type)
+                       snprintf(query, sizeof(query), "UPDATE %s SET log_type = log_type + 1 WHERE log_type = %d OR log_type = %d",
+                                       CTS_TABLE_PHONELOGS, CTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN,
+                                       CTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN);
+               else
+                       snprintf(query, sizeof(query), "UPDATE %s SET log_type = %d WHERE log_type = %d",
+                                       CTS_TABLE_PHONELOGS, type+1, type);
+       }
+       else {
+               snprintf(query, sizeof(query), "UPDATE %s SET log_type = %d WHERE id = %d",
+                               CTS_TABLE_PHONELOGS, type+1, index);
+       }
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       if (cts_db_change()) {
+               cts_set_plog_noti();
+               cts_set_missed_call_noti();
+       }
+
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+/**
+ * This is the signature of a callback function added with contats_svc_phonelog_get_all_number(),
+ * \n This function is invoked in the above functions.
+ * \n If this function doesn't return #CTS_SUCCESS, foreach function is terminated.
+ *
+ * @param[in] number number.
+ * @param[in] user_data The data which is set by contats_svc_phonelog_get_all_number(),
+ * @return #CTS_SUCCESS on success, other value on error
+ */
+typedef int (*cts_plog_foreach_fn)(const char *number, void *user_data);
+
+/**
+ * This function calls #cts_plog_foreach_fn for each number of all number list.
+ * The all number list doesn't have duplicated numbers.
+ *
+ * @param[in] cb callback function pointer(#cts_plog_foreach_fn)
+ * @param[in] user_data data which is passed to callback function
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+API int contats_svc_phonelog_get_all_number(cts_plog_foreach_fn cb,
+               void *user_data)
+{
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       retv_if(NULL == cb, CTS_ERR_ARG_NULL);
+
+       snprintf(query, sizeof(query),
+                       "SELECT DISTINCT number FROM %s", CTS_TABLE_PHONELOGS);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       while (CTS_TRUE == cts_stmt_step(stmt)) {
+               if (cb(cts_stmt_get_text(stmt, 0), user_data))
+                       break;
+       }
+       cts_stmt_finalize(stmt);
+
+       return CTS_SUCCESS;
+}
+
+API char* contacts_svc_phonelog_get_last_number(cts_plog_get_last_op op)
+{
+       int ret;
+       cts_stmt stmt;
+       char *number;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       switch (op) {
+       case CTS_PLOG_LAST_ALL:
+               snprintf(query, sizeof(query),
+                               "SELECT id, number FROM %s "
+                               "WHERE id = (SELECT MAX(id) FROM %s WHERE log_type = %d OR log_type = %d)",
+                               CTS_TABLE_PHONELOGS, CTS_TABLE_PHONELOGS,
+                               CTS_PLOG_TYPE_VOICE_OUTGOING, CTS_PLOG_TYPE_VIDEO_OUTGOING);
+               break;
+       case CTS_PLOG_LAST_CALL_ONLY:
+               snprintf(query, sizeof(query),
+                               "SELECT id, number FROM %s "
+                               "WHERE id = (SELECT MAX(id) FROM %s WHERE log_type = %d)",
+                               CTS_TABLE_PHONELOGS, CTS_TABLE_PHONELOGS, CTS_PLOG_TYPE_VOICE_OUTGOING);
+               break;
+       case CTS_PLOG_LAST_VIDEO_CALL_ONLY:
+               snprintf(query, sizeof(query),
+                               "SELECT id, number FROM %s "
+                               "WHERE id = (SELECT MAX(id) FROM %s WHERE log_type = %d)",
+                               CTS_TABLE_PHONELOGS, CTS_TABLE_PHONELOGS, CTS_PLOG_TYPE_VIDEO_OUTGOING);
+               break;
+       default:
+               ERR("Invalid op(%d)", op);
+               return NULL;
+       }
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, NULL, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return NULL;
+       }
+       number = SAFE_STRDUP(cts_stmt_get_text(stmt, 1));
+
+       cts_stmt_finalize(stmt);
+
+       return number;
+}
diff --git a/src/cts-phonelog.h b/src/cts-phonelog.h
new file mode 100755 (executable)
index 0000000..19b0a71
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_PHONELOG_H__
+#define __CTS_PHONELOG_H__
+
+//<!--
+/**
+ * @defgroup   CONTACTS_SVC_PLOG Phone Logs Modification
+ * @ingroup    CONTACTS_SVC
+ * @addtogroup CONTACTS_SVC_PLOG
+ * @{
+ *
+ * This interface provides methods to insert/update/delete the Phone Logs.
+ *
+ */
+
+/**
+ * This function inserts a phone log to database.
+ *
+ * @param[in] phone_log A phone log information of CTSvalue() created by contacts_svc_value_new(CTS_VALUE_PHONELOG).
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void phonelog_insert_test(void)
+ {
+    CTSvalue *plog;
+
+    plog = contacts_svc_value_new(CTS_VALUE_PHONELOG);
+    contacts_svc_value_set_str(plog, CTS_PLOG_VAL_NUMBER_STR, "0123456789");
+    contacts_svc_value_set_int(plog, CTS_PLOG_VAL_LOG_TIME_INT,(int) time(NULL));
+    contacts_svc_value_set_int(plog, CTS_PLOG_VAL_LOG_TYPE_INT,
+                                     CTS_PLOG_TYPE_VOICE_INCOMMING);
+    contacts_svc_value_set_int(plog, CTS_PLOG_VAL_DURATION_INT, 65);
+    contacts_svc_insert_phonelog(plog);
+
+    contacts_svc_value_set_str(plog, CTS_PLOG_VAL_NUMBER_STR, "0987654321");
+    contacts_svc_value_set_int(plog, CTS_PLOG_VAL_LOG_TIME_INT,(int) time(NULL));
+    contacts_svc_value_set_int(plog, CTS_PLOG_VAL_LOG_TYPE_INT,
+                                     CTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN);
+    contacts_svc_value_set_int(plog, CTS_PLOG_VAL_DURATION_INT, 65);
+    contacts_svc_insert_phonelog(plog);
+
+    contacts_svc_value_set_str(plog, CTS_PLOG_VAL_NUMBER_STR, "0987654321");
+    contacts_svc_value_set_int(plog, CTS_PLOG_VAL_LOG_TIME_INT,(int) time(NULL));
+    contacts_svc_value_set_int(plog, CTS_PLOG_VAL_LOG_TYPE_INT,
+                                     CTS_PLOG_TYPE_VOICE_INCOMMING);
+    contacts_svc_value_set_int(plog, CTS_PLOG_VAL_DURATION_INT, 65);
+    contacts_svc_insert_phonelog(plog);
+
+
+    contacts_svc_value_free(plog);
+ }
+ * @endcode
+ */
+int contacts_svc_insert_phonelog(CTSvalue* phone_log);
+
+/**
+ * Use for contacts_svc_delete_phonelog().
+ */
+typedef enum{
+       CTS_PLOG_DEL_BY_ID, /**< .*/
+       CTS_PLOG_DEL_BY_NUMBER, /**< .*/
+       CTS_PLOG_DEL_NO_NUMBER, /**< .*/
+       CTS_PLOG_DEL_BY_MSGID, /**< .*/
+}cts_del_plog_op;
+/**
+ * This function deletes a phone log with op_code(#CTS_PLOG_DEL_BY_ID, #CTS_PLOG_DEL_BY_NUMBER).
+ * @par int contacts_svc_delete_phonelog(CTS_PLOG_DEL_BY_ID, int index)
+ * @par int contacts_svc_delete_phonelog(CTS_PLOG_DEL_BY_NUMBER, char *number)
+ * Delete all phone logs related with number.
+ *
+ * @param[in] op_code #cts_del_plog_op
+ * @param[in] index (optional) Index of the phone log
+ * @param[in] number (optional) Number to be deleted
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ contacts_svc_delete_phonelog(CTS_PLOG_DEL_BY_ID, 3);
+ contacts_svc_delete_phonelog(CTS_PLOG_DEL_BY_NUMBER, "0123456789");
+ * @endcode
+ */
+int contacts_svc_delete_phonelog(cts_del_plog_op op_code, ...);
+
+/**
+ * This function modifies a phone log from unseen to seen.
+ * \n Type should be #CTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN or #CTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN
+ *
+ * @param[in] index Index of the phone log
+ * @param[in] type The current type of phone log
+ * @par example
+ * @code
+ contacts_svc_phonelog_set_seen(2, CTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN);
+ * @endcode
+ */
+int contacts_svc_phonelog_set_seen(int index, int type);
+
+/**
+ * Use for contacts_svc_phonelog_get_last_number().
+ */
+typedef enum{
+       CTS_PLOG_LAST_ALL, /**< .*/
+       CTS_PLOG_LAST_CALL_ONLY, /**< .*/
+       CTS_PLOG_LAST_VIDEO_CALL_ONLY, /**< .*/
+}cts_plog_get_last_op;
+
+/**
+ * This function gets the string of the most recent outgoing call number.
+ * \n It specifys by op(#cts_plog_get_last_op).
+ * \n It checks voice and video call(Not SMS/MMS).
+ * \n It doesn't include the rejected and blocked numbers.
+ * \n The obtained string should be free using by free().
+ * @return string of the last number, or NULL if no value is obtained or on error
+ */
+char* contacts_svc_phonelog_get_last_number(cts_plog_get_last_op op);
+
+/**
+ * This function gets phonelog record which has the index from the database.
+ * Obtained phonelog record should be freed by using contacts_svc_value_free().
+ * @param[in] plog_id The index of phonelog to get
+ * @param[out] phonelog Points of the phonelog record which is returned
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+ void get_phonelog(void)
+ {
+    int ret;
+    CTSvalue *plog;
+
+    ret = contacts_svc_get_phonelog(1, &plog);
+    if(ret < 0)
+    {
+       printf("No found record\n");
+       return;
+    }
+
+    printf("Number : %s\n", contacts_svc_value_get_str(plog, CTS_PLOG_VAL_NUMBER_STR));
+    printf("Related ID : %d\n", contacts_svc_value_get_int(plog, CTS_PLOG_VAL_ID_INT));
+    printf("Time : %d\n", contacts_svc_value_get_int(plog, CTS_PLOG_VAL_LOG_TIME_INT));
+    printf("Type : %d\n", contacts_svc_value_get_int(plog, CTS_PLOG_VAL_LOG_TYPE_INT));
+    printf("Duration : %d\n", contacts_svc_value_get_int(plog, CTS_PLOG_VAL_DURATION_INT));
+    printf("Related ID : %d\n", contacts_svc_value_get_int(plog, CTS_PLOG_VAL_RELATED_ID_INT));
+
+    contacts_svc_value_free(plog);
+ }
+ * @endcode
+ */
+int contacts_svc_get_phonelog(int plog_id, CTSvalue **phonelog);
+
+/**
+ * @}
+ */
+
+//-->
+
+#endif //__CTS_PHONELOG_H__
+
diff --git a/src/cts-pthread.c b/src/cts-pthread.c
new file mode 100755 (executable)
index 0000000..14a073c
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <pthread.h>
+
+#include "cts-internal.h"
+#include "cts-pthread.h"
+
+typedef struct {
+       int (* lock) (pthread_mutex_t *mutex);
+       int (* unlock) (pthread_mutex_t *mutex);
+}cts_thread_fns;
+
+static cts_thread_fns cts_thread_funtions =
+{
+       pthread_mutex_lock,
+       pthread_mutex_unlock
+};
+
+static pthread_mutex_t conn_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t sockfd_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static inline pthread_mutex_t* cts_pthread_get_mutex(int type)
+{
+       pthread_mutex_t *ret_val;
+
+       switch (type) {
+       case CTS_MUTEX_CONNECTION:
+               ret_val = &conn_mutex;
+               break;
+       case CTS_MUTEX_SOCKET_FD:
+               ret_val = &sockfd_mutex;
+               break;
+       default:
+               ERR("unknown type(%d)", type);
+               ret_val = NULL;
+       }
+       return ret_val;
+}
+
+void cts_mutex_lock(int type)
+{
+       int ret;
+       pthread_mutex_t *mutex;
+
+       mutex = cts_pthread_get_mutex(type);
+
+       if (cts_thread_funtions.lock) {
+               ret = cts_thread_funtions.lock(mutex);
+               warn_if(ret, "pthread_mutex_lock Failed(%d)", ret);
+       }
+}
+
+void cts_mutex_unlock(int type)
+{
+       int ret;
+       pthread_mutex_t *mutex;
+
+       mutex = cts_pthread_get_mutex(type);
+
+       if (cts_thread_funtions.unlock) {
+               ret = cts_thread_funtions.unlock(mutex);
+               warn_if(ret, "pthread_mutex_unlock Failed(%d)", ret);
+       }
+}
+
+void contacts_svc_thread_init(void)
+{
+       cts_thread_funtions.lock = pthread_mutex_lock;
+       cts_thread_funtions.unlock = pthread_mutex_unlock;
+}
diff --git a/src/cts-pthread.h b/src/cts-pthread.h
new file mode 100755 (executable)
index 0000000..16a5132
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_PTHREAD_H__
+#define __CTS_PTHREAD_H__
+
+enum {
+       CTS_MUTEX_CONNECTION,
+       CTS_MUTEX_UPDTATED_LIST_MEMPOOL,
+       CTS_MUTEX_SOCKET_FD,
+};
+
+void cts_mutex_lock(int type);
+void cts_mutex_unlock(int type);
+
+
+#endif //__CTS_PTHREAD_H__
+
diff --git a/src/cts-schema.h b/src/cts-schema.h
new file mode 100755 (executable)
index 0000000..8f72597
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_SCHEMA_H__
+#define __CTS_SCHEMA_H__
+
+#define CTS_DB_PATH "/opt/dbspace/.contacts-svc.db"
+#define CTS_DB_JOURNAL_PATH "/opt/dbspace/.contacts-svc.db-journal"
+
+// For Security
+#define CTS_SECURITY_FILE_GROUP 6005
+#define CTS_SECURITY_DEFAULT_PERMISSION 0660
+#define CTS_SECURITY_DIR_DEFAULT_PERMISSION 0770
+
+#define CTS_SCHEMA_TABLE_TOTAL 10
+
+// Tables
+#define CTS_TABLE_CONTACTS "contacts"
+#define CTS_TABLE_GROUPS "groups"
+#define CTS_TABLE_ADDRESSBOOKS "addressbooks"
+#define CTS_TABLE_DATA "data"     // This is the data table for contact all fields
+#define CTS_TABLE_FAVORITES "favorites"
+#define CTS_TABLE_PHONELOGS "phonelogs"
+#define CTS_TABLE_PHONELOG_ACC "phonelog_accumulation"
+#define CTS_TABLE_GROUPING_INFO "group_relations"
+#define CTS_TABLE_DELETEDS "deleteds"
+#define CTS_TABLE_CUSTOM_TYPES "custom_types"
+#define CTS_TABLE_SIM_SERVICES "sim_services"
+#define CTS_TABLE_SPEEDDIALS "speeddials"
+#define CTS_TABLE_VERSION "cts_version"
+
+#define CTS_SCHEMA_DATA_NAME_LANG_INFO "data1"
+#define CTS_SCHEMA_DATA_NAME_LOOKUP "data8"
+#define CTS_SCHEMA_DATA_NAME_REVERSE_LOOKUP "data9"
+#define CTS_SCHEMA_DATA_NAME_SORTING_KEY "data10"
+
+#define CTS_SCHEMA_SQLITE_SEQ "sqlite_sequence"
+
+
+#endif /* __CTS_SCHEMA_H__ */
+
diff --git a/src/cts-service.c b/src/cts-service.c
new file mode 100755 (executable)
index 0000000..280716c
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <stdarg.h>
+#include <dlfcn.h>
+
+#include "cts-internal.h"
+#include "cts-schema.h"
+#include "cts-sqlite.h"
+#include "cts-utils.h"
+#include "cts-service.h"
+#include "cts-socket.h"
+#include "cts-normalize.h"
+#include "cts-list.h"
+#include "cts-pthread.h"
+
+static int cts_conn_refcnt = 0;
+
+API int contacts_svc_connect(void)
+{
+       CTS_FN_CALL;
+       int ret;
+
+       cts_mutex_lock(CTS_MUTEX_CONNECTION);
+       if (0 < cts_conn_refcnt) {
+               CTS_DBG("The contacts-service is already connected. refcnt=%d", cts_conn_refcnt);
+               cts_conn_refcnt++;
+       }
+       else
+       {
+               ret = cts_socket_init();
+               if (CTS_SUCCESS != ret) {
+                       void *handle, *fn;
+                       handle = dlopen(NULL, RTLD_GLOBAL);
+                       fn = dlsym(handle, "cts_helper_normalize_name");
+                       if (NULL == fn) {
+                               ERR("cts_socket_init() Failed(%d)", ret);
+                               cts_mutex_unlock(CTS_MUTEX_CONNECTION);
+                               return ret;
+                       }
+                       cts_set_extra_normalize_fn(fn);
+               }
+
+               ret = cts_db_open();
+               if (ret != CTS_SUCCESS) {
+                       ERR("cts_db_open() Failed(%d)", ret);
+                       cts_socket_final();
+                       cts_mutex_unlock(CTS_MUTEX_CONNECTION);
+                       return ret;
+               }
+
+               cts_register_noti();
+               cts_conn_refcnt = 1;
+       }
+       cts_mutex_unlock(CTS_MUTEX_CONNECTION);
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_disconnect(void)
+{
+       CTS_FN_CALL;
+       retvm_if(0 == cts_conn_refcnt, CTS_ERR_ENV_INVALID,
+                       "Contacts service was not connected");
+       CTS_DBG("CTS DB refcnt = %d", cts_conn_refcnt);
+
+       cts_mutex_lock(CTS_MUTEX_CONNECTION);
+       if (1 == cts_conn_refcnt)
+       {
+               cts_socket_final();
+               cts_deregister_noti();
+               cts_db_close();
+               cts_conn_refcnt--;
+       }
+       else
+               cts_conn_refcnt--;
+       cts_mutex_unlock(CTS_MUTEX_CONNECTION);
+
+       return CTS_SUCCESS;
+}
+
+#if 0
+typedef enum {
+       CTS_DELETE_ALL_CONTACT_OF_ACCOUNT,
+       CTS_DELETE_ALL_GROUP_OF_ACCOUNT,
+       CTS_DELETE_ALL_PLOG
+};
+int contacts_svc_delete_all(int op_code, int index)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       switch (op_code)
+       {
+       case CTS_DELETE_ALL_CONTACT_OF_ACCOUNT:
+               snprintf(query, sizeof(query),
+                               "DELETE FROM %s WHERE account_id=%d"
+                               CTS_TABLE_CONTACTS, CTS_SCHEMA_NUMBERS, CTS_PLOG_TYPE_MMS_INCOMMING);
+               break;
+       case CTS_DELETE_ALL_GROUP_OF_ACCOUNT:
+       default:
+               ERR("Invalid op_code. Your op_code(%d) is not supported.", op_code);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+
+}
+#endif
diff --git a/src/cts-service.h b/src/cts-service.h
new file mode 100755 (executable)
index 0000000..3c358e8
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_SERVICE_H__
+#define __CTS_SERVICE_H__
+
+//<!--
+/**
+ * This function connect to contacts service.
+ * \n Though the connection already exists, #CTS_SUCCESS is returned.
+ * \n It has to disconnect as it connect.
+ * for example, if you connect 3 times you have to disconnect 3times.
+ * \n To disconnect early minimizes the runtime resource consumption.
+ * On the other hand, a pair of connection and disconnection is expensive.
+ * Don't call frequently.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @see contacts_svc_disconnect()
+ */
+int contacts_svc_connect(void);
+
+/**
+ * This function disconnect to contacts service.
+ * If connection is called many times,
+ * disconnection operation is valid at the last of the times.
+ *
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @see contacts_svc_connect()
+ */
+int contacts_svc_disconnect(void);
+//-->
+
+#endif //__CTS_SERVICE_H__
diff --git a/src/cts-socket.c b/src/cts-socket.c
new file mode 100755 (executable)
index 0000000..29dbf8c
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "cts-internal.h"
+#include "cts-normalize.h"
+#include "cts-socket.h"
+
+static int cts_csockfd = -1;
+
+static inline int cts_safe_write(int fd, const char *buf, int buf_size)
+{
+       int ret, writed=0;
+       while (buf_size) {
+               ret = write(fd, buf+writed, buf_size);
+               if (-1 == ret) {
+                       if (EINTR == errno)
+                               continue;
+                       else
+                               return ret;
+               }
+               writed += ret;
+               buf_size -= ret;
+       }
+       return writed;
+}
+
+static inline int cts_safe_read(int fd, char *buf, int buf_size)
+{
+       int ret, read_size=0;
+       while (buf_size) {
+               ret = read(fd, buf+read_size, buf_size);
+               if (-1 == ret) {
+                       if (EINTR == errno)
+                               continue;
+                       else
+                               return ret;
+               }
+               read_size += ret;
+               buf_size -= ret;
+       }
+       return read_size;
+}
+
+static int cts_socket_handle_return(int fd, cts_socket_msg *msg)
+{
+       CTS_FN_CALL;
+       int ret;
+
+       ret = cts_safe_read(fd, (char *)msg, sizeof(cts_socket_msg));
+       retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "cts_safe_read() Failed(errno = %d)", errno);
+
+       warn_if(CTS_REQUEST_RETURN_VALUE != msg->type,
+                       "Unknown Type(%d), ret=%d, attach_num= %d,"
+                       "attach1 = %d, attach2 = %d, attach3 = %d, attach4 = %d",
+                       msg->type, msg->val, msg->attach_num,
+                       msg->attach_sizes[0],msg->attach_sizes[1],msg->attach_sizes[2],
+                       msg->attach_sizes[3]);
+
+       retvm_if(CTS_REQUEST_MAX_ATTACH < msg->attach_num, CTS_ERR_SOCKET_FAILED,
+                       "Invalid msg(attach_num = %d)", msg->attach_num);
+
+       return CTS_SUCCESS;
+}
+
+static void cts_remove_invalid_msg(int fd, int size)
+{
+       int ret;
+       char dummy[CTS_SOCKET_MSG_SIZE];
+
+       while (size) {
+               if (sizeof(dummy) < size) {
+                       ret = read(fd, dummy, sizeof(dummy));
+                       if (-1 == ret) {
+                               if (EINTR == errno)
+                                       continue;
+                               else
+                                       return;
+                       }
+                       size -= ret;
+               }
+               else {
+                       ret = read(fd, dummy, size);
+                       if (-1 == ret) {
+                               if (EINTR == errno)
+                                       continue;
+                               else
+                                       return;
+                       }
+                       size -= ret;
+               }
+       }
+}
+
+int cts_request_sim_import(void)
+{
+       int i, ret;
+       cts_socket_msg msg={0};
+
+       retvm_if(-1 == cts_csockfd, CTS_ERR_ENV_INVALID, "socket is not connected");
+
+       msg.type = CTS_REQUEST_IMPORT_SIM;
+       ret = cts_safe_write(cts_csockfd, (char *)&msg, sizeof(msg));
+       retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "cts_safe_write() Failed(errno = %d)", errno);
+
+       ret = cts_socket_handle_return(cts_csockfd, &msg);
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_socket_handle_return() Failed(%d)", ret);
+       CTS_DBG("attach_num = %d", msg.attach_num);
+
+       for (i=0;i<msg.attach_num;i++)
+               cts_remove_invalid_msg(cts_csockfd, msg.attach_sizes[i]);
+
+       return msg.val;
+}
+
+int cts_request_normalize_str(const char *src, char *dest, int dest_size)
+{
+       int i, ret;
+       cts_socket_msg msg={0};
+
+       retvm_if(-1 == cts_csockfd, CTS_ERR_ENV_INVALID, "socket is not connected");
+
+       msg.type = CTS_REQUEST_NORMALIZE_STR;
+       msg.attach_num = CTS_NS_ATTACH_NUM;
+       msg.attach_sizes[0] = strlen(src);
+       if (0 == msg.attach_sizes[0]) {
+               ERR("The parameter(src) is empty string");
+               dest[0] = '\0';
+               return CTS_SUCCESS;
+       }
+
+       ret = cts_safe_write(cts_csockfd, (char *)&msg, sizeof(msg));
+       retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "cts_safe_write() Failed(errno = %d)", errno);
+       ret = cts_safe_write(cts_csockfd, src, msg.attach_sizes[0]);
+       retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "cts_safe_write() Failed(errno = %d)", errno);
+       CTS_DBG("Send message : %s(%d)", src, msg.attach_sizes[0]);
+
+       ret = cts_socket_handle_return(cts_csockfd, &msg);
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_socket_handle_return() Failed(%d)", ret);
+
+       warn_if(CTS_NS_ATTACH_NUM != msg.attach_num,
+                       "Invalid attachments(attach_num = %d)", msg.attach_num);
+
+       if (dest_size <= msg.attach_sizes[0]) {
+               ret = cts_safe_read(cts_csockfd, dest, dest_size);
+               retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "cts_safe_read() Failed(errno = %d)", errno);
+
+               msg.attach_sizes[0] -= ret;
+               dest[dest_size-1] = '\0';
+               cts_remove_invalid_msg(cts_csockfd, msg.attach_sizes[0]);
+       }
+       else {
+               ret = cts_safe_read(cts_csockfd, dest, msg.attach_sizes[0]);
+               retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "cts_safe_read() Failed(errno = %d)", errno);
+
+               dest[msg.attach_sizes[0]] = '\0';
+       }
+
+       for (i=CTS_NS_ATTACH_NUM;i<msg.attach_num;i++)
+               cts_remove_invalid_msg(cts_csockfd, msg.attach_sizes[i]);
+
+       return msg.val;
+}
+
+int cts_request_normalize_name(char dest[][CTS_SQL_MAX_LEN])
+{
+       int i, ret;
+       cts_socket_msg msg={0};
+
+       retvm_if(-1 == cts_csockfd, CTS_ERR_ENV_INVALID, "socket is not connected");
+
+       msg.type = CTS_REQUEST_NORMALIZE_NAME;
+       msg.attach_num = CTS_NN_ATTACH_NUM;
+       msg.attach_sizes[CTS_NN_FIRST] = strlen(dest[CTS_NN_FIRST]);
+       msg.attach_sizes[CTS_NN_LAST] = strlen(dest[CTS_NN_LAST]);
+       msg.attach_sizes[CTS_NN_SORTKEY] = strlen(dest[CTS_NN_SORTKEY]);
+
+       if (!msg.attach_sizes[CTS_NN_FIRST] && !msg.attach_sizes[CTS_NN_LAST]){
+               return CTS_SUCCESS;
+       }
+       ret = cts_safe_write(cts_csockfd, (char *)&msg, sizeof(msg));
+       retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "cts_safe_write() Failed(errno = %d)", errno);
+       ret = cts_safe_write(cts_csockfd, dest[CTS_NN_FIRST], msg.attach_sizes[CTS_NN_FIRST]);
+       retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "cts_safe_write() Failed(errno = %d)", errno);
+       ret = cts_safe_write(cts_csockfd, dest[CTS_NN_LAST], msg.attach_sizes[CTS_NN_LAST]);
+       retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "cts_safe_write() Failed(errno = %d)", errno);
+       ret = cts_safe_write(cts_csockfd, dest[CTS_NN_SORTKEY], msg.attach_sizes[CTS_NN_SORTKEY]);
+       retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "cts_safe_write() Failed(errno = %d)", errno);
+       CTS_DBG("request_first = %s(%d), request_last = %s(%d), request_sortkey = %s(%d)",
+                       dest[CTS_NN_FIRST], msg.attach_sizes[CTS_NN_FIRST],
+                       dest[CTS_NN_LAST], msg.attach_sizes[CTS_NN_LAST],
+                       dest[CTS_NN_SORTKEY], msg.attach_sizes[CTS_NN_SORTKEY]);
+
+       ret = cts_socket_handle_return(cts_csockfd, &msg);
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_socket_handle_return() Failed(%d)", ret);
+
+       if (CTS_NN_MAX < msg.attach_num) {
+               ERR("Invalid attachments(attach_num = %d)", msg.attach_num);
+
+               for (i=0;i<msg.attach_num;i++)
+                       cts_remove_invalid_msg(cts_csockfd, msg.attach_sizes[i]);
+               return CTS_ERR_MSG_INVALID;
+       }
+
+       for (i=0;i<msg.attach_num;i++)
+       {
+               CTS_DBG("msg_size = %d", msg.attach_sizes[i]);
+               if (CTS_SQL_MAX_LEN <= msg.attach_sizes[i])
+               {
+                       ret = cts_safe_read(cts_csockfd, dest[i], sizeof(dest[i]));
+                       retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "cts_safe_read() Failed(errno = %d)", errno);
+
+                       msg.attach_sizes[i] -= ret;
+                       dest[i][CTS_SQL_MAX_LEN-1] = '\0';
+                       cts_remove_invalid_msg(cts_csockfd, msg.attach_sizes[i]);
+               }
+               else {
+                       ret = cts_safe_read(cts_csockfd, dest[i], msg.attach_sizes[i]);
+                       retvm_if(-1 == ret, CTS_ERR_SOCKET_FAILED, "cts_safe_read() Failed(errno = %d)", errno);
+
+                       dest[i][msg.attach_sizes[i]] = '\0';
+               }
+       }
+
+       return msg.val;
+}
+
+int cts_socket_init(void)
+{
+       int ret;
+       struct sockaddr_un caddr;
+
+       bzero(&caddr, sizeof(caddr));
+       caddr.sun_family = AF_UNIX;
+       snprintf(caddr.sun_path, sizeof(caddr.sun_path), "%s", CTS_SOCKET_PATH);
+
+       cts_csockfd = socket(PF_UNIX, SOCK_STREAM, 0);
+       retvm_if(-1 == cts_csockfd, CTS_ERR_SOCKET_FAILED,
+                       "socket() Failed(errno = %d)", errno);
+
+       ret = connect(cts_csockfd, (struct sockaddr *)&caddr, sizeof(caddr));
+       if (-1 == ret) {
+               ERR("connect() Failed(errno = %d)", errno);
+               close(cts_csockfd);
+               cts_csockfd = -1;
+               return CTS_ERR_SOCKET_FAILED;
+       }
+
+       return CTS_SUCCESS;
+}
+
+void cts_socket_final(void)
+{
+       close(cts_csockfd);
+       cts_csockfd = -1;
+}
diff --git a/src/cts-socket.h b/src/cts-socket.h
new file mode 100755 (executable)
index 0000000..4aa8278
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_SOCKET_H__
+#define __CTS_SOCKET_H__
+
+#include "cts-struct.h"
+#include "cts-sqlite.h"
+
+#define CTS_SOCKET_PATH "/opt/data/contacts-svc/.contacts-svc.sock"
+#define CTS_SOCKET_MSG_SIZE 128
+
+//Message TYPE
+enum{
+       CTS_REQUEST_RETURN_VALUE,
+       CTS_REQUEST_IMPORT_SIM,
+       CTS_REQUEST_NORMALIZE_STR,
+       CTS_REQUEST_NORMALIZE_NAME,
+};
+//#define CTS_REQUEST_IMPORT_SIM "cts_request_import_sim"
+//#define CTS_REQUEST_NORMALIZE_STR "cts_request_normalize_str"
+//#define CTS_REQUEST_RETURN_VALUE "cts_request_return_value"
+#define CTS_REQUEST_MAX_ATTACH 5
+
+#define CTS_NS_ATTACH_NUM 1 //NS = Normalize String
+#define CTS_NN_ATTACH_NUM 3 //NN = Normalize Name
+
+typedef struct{
+       int type;
+       int val;
+       int attach_num;
+       int attach_sizes[CTS_REQUEST_MAX_ATTACH];
+}cts_socket_msg;
+
+int cts_socket_init(void);
+int cts_request_normalize_name(char dest[][CTS_SQL_MAX_LEN]);
+int cts_request_normalize_str(const char * src, char * dest, int dest_size);
+int cts_request_sim_import(void);
+void cts_socket_final(void);
+
+#endif //__CTS_SOCKET_H__
+
diff --git a/src/cts-sqlite.c b/src/cts-sqlite.c
new file mode 100755 (executable)
index 0000000..48eebbd
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <string.h>
+#include <db-util.h>
+
+#include "cts-internal.h"
+#include "cts-schema.h"
+#include "cts-sqlite.h"
+
+static sqlite3 *cts_db;
+
+int cts_db_open(void)
+{
+       CTS_FN_CALL;
+       int ret;
+
+       if (!cts_db) {
+               ret = db_util_open(CTS_DB_PATH, &cts_db, 0);
+               retvm_if(SQLITE_OK != ret, CTS_ERR_DB_NOT_OPENED,
+                               "db_util_open() Failed(%d)", ret);
+       }
+       return CTS_SUCCESS;
+}
+
+int cts_db_close(void)
+{
+       int ret = 0;
+
+       if (cts_db) {
+               ret = db_util_close(cts_db);
+               warn_if(SQLITE_OK != ret, "db_util_close() Failed(%d)", ret);
+               cts_db = NULL;
+               CTS_DBG("The database disconnected really.");
+       }
+
+       return CTS_SUCCESS;
+}
+
+int cts_db_change(void)
+{
+       return sqlite3_changes(cts_db);
+}
+
+int cts_db_get_last_insert_id(void)
+{
+       return sqlite3_last_insert_rowid(cts_db);
+}
+
+int cts_db_get_next_id(const char *table)
+{
+       int ret;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       snprintf(query, sizeof(query), "SELECT seq FROM %s WHERE name = '%s'",
+                       CTS_SCHEMA_SQLITE_SEQ, table);
+
+       ret = cts_query_get_first_int_result(query);
+       if (ret < CTS_SUCCESS) {
+               if (CTS_ERR_DB_RECORD_NOT_FOUND == ret)
+                       return 1;
+               else
+                       return ret;
+       } else {
+               return (1 + ret);
+       }
+}
+
+int cts_query_get_first_int_result(const char *query)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       retvm_if(NULL == cts_db, CTS_ERR_DB_NOT_OPENED, "Database is not opended");
+
+       ret = sqlite3_prepare_v2(cts_db, query, strlen(query), &stmt, NULL);
+       retvm_if(SQLITE_OK != ret, CTS_ERR_DB_FAILED,
+                       "sqlite3_prepare_v2(%s) Failed(%s)", query, sqlite3_errmsg(cts_db));
+
+       ret = sqlite3_step(stmt);
+       if (SQLITE_ROW != ret) {
+               ERR("sqlite3_step() Failed(%d, %s)", ret, sqlite3_errmsg(cts_db));
+               sqlite3_finalize(stmt);
+               if (SQLITE_DONE == ret) return CTS_ERR_DB_RECORD_NOT_FOUND;
+               return CTS_ERR_DB_FAILED;
+       }
+
+       ret = sqlite3_column_int(stmt, 0);
+       sqlite3_finalize(stmt);
+
+       return ret;
+}
+
+int cts_query_exec(char *query)
+{
+       int ret;
+       char *err_msg = NULL;
+
+       retvm_if(NULL == cts_db, CTS_ERR_DB_NOT_OPENED, "Database is not opended");
+       CTS_DBG("query : %s", query);
+
+       ret = sqlite3_exec(cts_db, query, NULL, NULL, &err_msg);
+       if (SQLITE_OK != ret) {
+               ERR("sqlite3_exec(%s) Failed(%d, %s)", query, ret, err_msg);
+               sqlite3_free(err_msg);
+               switch (ret) {
+               case SQLITE_BUSY:
+               case SQLITE_LOCKED:
+                       return CTS_ERR_DB_LOCK;
+               case SQLITE_IOERR:
+                       return CTS_ERR_IO_ERR;
+               case SQLITE_FULL:
+                       return CTS_ERR_NO_SPACE;
+               default:
+                       return CTS_ERR_DB_FAILED;
+               }
+       }
+
+       return CTS_SUCCESS;
+}
+
+cts_stmt cts_query_prepare(char *query)
+{
+       int ret = -1;
+       cts_stmt stmt = NULL;
+
+       retvm_if(NULL == cts_db, NULL, "Database is not opended");
+       CTS_DBG("prepare query : %s", query);
+
+       ret = sqlite3_prepare_v2(cts_db, query, strlen(query), &stmt, NULL);
+       retvm_if(SQLITE_OK != ret, NULL,
+                       "sqlite3_prepare_v2(%s) Failed(%s)", query, sqlite3_errmsg(cts_db));
+
+       return stmt;
+}
+
+int cts_stmt_get_first_int_result(cts_stmt stmt)
+{
+       int ret;
+       retvm_if(NULL == cts_db, CTS_ERR_DB_NOT_OPENED, "Database is not opended");
+
+       ret = sqlite3_step(stmt);
+       if (SQLITE_ROW != ret) {
+               ERR("sqlite3_step() Failed(%d, %s)", ret, sqlite3_errmsg(cts_db));
+               sqlite3_finalize(stmt);
+               if (SQLITE_DONE == ret) return CTS_ERR_DB_RECORD_NOT_FOUND;
+               return CTS_ERR_DB_FAILED;
+       }
+
+       ret = sqlite3_column_int(stmt, 0);
+       sqlite3_finalize(stmt);
+
+       return ret;
+}
+
+int cts_stmt_step(cts_stmt stmt)
+{
+       int ret;
+       ret = sqlite3_step(stmt);
+       switch (ret) {
+       case SQLITE_BUSY:
+       case SQLITE_LOCKED:
+               ret = CTS_ERR_DB_LOCK;
+               break;
+       case SQLITE_IOERR:
+               ret = CTS_ERR_IO_ERR;
+               break;
+       case SQLITE_FULL:
+               ret = CTS_ERR_NO_SPACE;
+               break;
+       case SQLITE_CONSTRAINT:
+               ret = CTS_ERR_ALREADY_EXIST;
+               break;
+       case SQLITE_ROW:
+               ret = CTS_TRUE;
+               break;
+       case SQLITE_DONE:
+               ret = CTS_SUCCESS;
+               break;
+       default:
+               ERR("sqlite3_step() Failed(%d)", ret);
+               ret = CTS_ERR_DB_FAILED;
+               break;
+       }
+       return ret;
+}
+
+void cts_stmt_reset(cts_stmt stmt)
+{
+       sqlite3_reset(stmt);
+       sqlite3_clear_bindings(stmt);
+}
+
+void cts_stmt_finalize(cts_stmt stmt)
+{
+       int ret;
+
+       if (NULL == stmt)
+               return;
+
+       ret = sqlite3_finalize(stmt);
+       warn_if(ret != SQLITE_OK,
+                       "sqlite3_finalize Failed(%d, %s)", ret, sqlite3_errmsg(cts_db));
+}
+
+
+int cts_stmt_bind_name(cts_stmt stmt, int start_cnt, cts_name *name_struct)
+{
+       if (name_struct->first)
+               sqlite3_bind_text(stmt, start_cnt+1, name_struct->first,
+                               strlen(name_struct->first), SQLITE_STATIC);
+       if (name_struct->last)
+               sqlite3_bind_text(stmt, start_cnt+2, name_struct->last,
+                               strlen(name_struct->last), SQLITE_STATIC);
+       if (name_struct->addition)
+               sqlite3_bind_text(stmt, start_cnt+3, name_struct->addition,
+                               strlen(name_struct->addition), SQLITE_STATIC);
+       if (name_struct->display)
+               sqlite3_bind_text(stmt, start_cnt+4, name_struct->display,
+                               strlen(name_struct->display), SQLITE_STATIC);
+       if (name_struct->prefix)
+               sqlite3_bind_text(stmt, start_cnt+5, name_struct->prefix,
+                               strlen(name_struct->prefix), SQLITE_STATIC);
+       if (name_struct->suffix)
+               sqlite3_bind_text(stmt, start_cnt+6, name_struct->suffix,
+                               strlen(name_struct->suffix), SQLITE_STATIC);
+       return start_cnt+7;
+}
+
+int cts_stmt_bind_event(cts_stmt stmt, int start_cnt, cts_event *event_struct)
+{
+       sqlite3_bind_int(stmt, start_cnt++, event_struct->type);
+       sqlite3_bind_int(stmt, start_cnt++, event_struct->date);
+       return CTS_SUCCESS;
+}
+
+int cts_stmt_bind_messenger(cts_stmt stmt, int start_cnt, cts_messenger *im_struct)
+{
+       sqlite3_bind_int(stmt, start_cnt++, im_struct->type);
+       if (im_struct->im_id)
+               sqlite3_bind_text(stmt, start_cnt++, im_struct->im_id,
+                               strlen(im_struct->im_id), SQLITE_STATIC);
+       return CTS_SUCCESS;
+}
+
+int cts_stmt_bind_postal(cts_stmt stmt, int start_cnt, cts_postal *postal_struct)
+{
+       sqlite3_bind_int(stmt, start_cnt, postal_struct->type);
+       if (postal_struct->pobox)
+               sqlite3_bind_text(stmt, start_cnt+1, postal_struct->pobox,
+                               strlen(postal_struct->pobox), SQLITE_STATIC);
+       if (postal_struct->postalcode)
+               sqlite3_bind_text(stmt, start_cnt+2, postal_struct->postalcode,
+                               strlen(postal_struct->postalcode), SQLITE_STATIC);
+       if (postal_struct->region)
+               sqlite3_bind_text(stmt, start_cnt+3, postal_struct->region,
+                               strlen(postal_struct->region), SQLITE_STATIC);
+       if (postal_struct->locality)
+               sqlite3_bind_text(stmt, start_cnt+4, postal_struct->locality,
+                               strlen(postal_struct->locality), SQLITE_STATIC);
+       if (postal_struct->street)
+               sqlite3_bind_text(stmt, start_cnt+5, postal_struct->street,
+                               strlen(postal_struct->street), SQLITE_STATIC);
+       if (postal_struct->extended)
+               sqlite3_bind_text(stmt, start_cnt+6, postal_struct->extended,
+                               strlen(postal_struct->extended), SQLITE_STATIC);
+       if (postal_struct->country)
+               sqlite3_bind_text(stmt, start_cnt+7, postal_struct->country,
+                               strlen(postal_struct->country), SQLITE_STATIC);
+       return CTS_SUCCESS;
+}
+
+int cts_stmt_bind_company(cts_stmt stmt, int start_cnt, cts_company *company_struct)
+{
+       if (company_struct->name)
+               sqlite3_bind_text(stmt, start_cnt+1, company_struct->name,
+                               strlen(company_struct->name), SQLITE_STATIC);
+       if (company_struct->department)
+               sqlite3_bind_text(stmt, start_cnt+2, company_struct->department,
+                               strlen(company_struct->department), SQLITE_STATIC);
+       if (company_struct->jot_title)
+               sqlite3_bind_text(stmt, start_cnt+3, company_struct->jot_title,
+                               strlen(company_struct->jot_title), SQLITE_STATIC);
+       if (company_struct->role)
+               sqlite3_bind_text(stmt, start_cnt+4, company_struct->role,
+                               strlen(company_struct->role), SQLITE_STATIC);
+       if (company_struct->assistant_name)
+               sqlite3_bind_text(stmt, start_cnt+5, company_struct->assistant_name,
+                               strlen(company_struct->assistant_name), SQLITE_STATIC);
+       return CTS_SUCCESS;
+}
+
+int cts_stmt_bind_web(cts_stmt stmt, int start_cnt, cts_web *web_struct)
+{
+       sqlite3_bind_int(stmt, start_cnt++, web_struct->type);
+       if (web_struct->url)
+               sqlite3_bind_text(stmt, start_cnt++, web_struct->url,
+                               strlen(web_struct->url), SQLITE_STATIC);
+       return CTS_SUCCESS;
+}
+
+int cts_stmt_bind_extend(cts_stmt stmt, int start_cnt, cts_extend *extend_struct)
+{
+       sqlite3_bind_int(stmt, start_cnt, extend_struct->data1);
+       if (extend_struct->data2)
+               sqlite3_bind_text(stmt, start_cnt+1, extend_struct->data2,
+                               strlen(extend_struct->data2), SQLITE_STATIC);
+       if (extend_struct->data3)
+               sqlite3_bind_text(stmt, start_cnt+2, extend_struct->data3,
+                               strlen(extend_struct->data3), SQLITE_STATIC);
+       if (extend_struct->data4)
+               sqlite3_bind_text(stmt, start_cnt+3, extend_struct->data4,
+                               strlen(extend_struct->data4), SQLITE_STATIC);
+       if (extend_struct->data5)
+               sqlite3_bind_text(stmt, start_cnt+4, extend_struct->data5,
+                               strlen(extend_struct->data5), SQLITE_STATIC);
+       if (extend_struct->data6)
+               sqlite3_bind_text(stmt, start_cnt+5, extend_struct->data6,
+                               strlen(extend_struct->data6), SQLITE_STATIC);
+       if (extend_struct->data7)
+               sqlite3_bind_text(stmt, start_cnt+6, extend_struct->data7,
+                               strlen(extend_struct->data7), SQLITE_STATIC);
+       if (extend_struct->data8)
+               sqlite3_bind_text(stmt, start_cnt+7, extend_struct->data8,
+                               strlen(extend_struct->data8), SQLITE_STATIC);
+       if (extend_struct->data9)
+               sqlite3_bind_text(stmt, start_cnt+8, extend_struct->data9,
+                               strlen(extend_struct->data9), SQLITE_STATIC);
+       if (extend_struct->data10)
+               sqlite3_bind_text(stmt, start_cnt+9, extend_struct->data10,
+                               strlen(extend_struct->data10), SQLITE_STATIC);
+       return CTS_SUCCESS;
+}
+
+int cts_stmt_get_addressbook(cts_stmt stmt, cts_addrbook *ab)
+{
+       int cnt = 0;
+       char *temp;
+
+       ab->id = cts_stmt_get_int(stmt, cnt++);
+       temp = cts_stmt_get_text(stmt, cnt++);
+       ab->name = SAFE_STRDUP(temp);
+       ab->acc_id = cts_stmt_get_int(stmt, cnt++);
+       ab->acc_type = cts_stmt_get_int(stmt, cnt++);
+       ab->mode = cts_stmt_get_int(stmt, cnt++);
+
+       return CTS_SUCCESS;
+}
+
+int cts_stmt_get_number(cts_stmt stmt, cts_number *result, int start_cnt)
+{
+       char *temp;
+
+       result->id = cts_stmt_get_int(stmt, start_cnt++);
+       result->type = cts_stmt_get_int(stmt, start_cnt++);
+       temp = cts_stmt_get_text(stmt, start_cnt++);
+       result->number = SAFE_STRDUP(temp);
+
+       return start_cnt;
+}
+
+int cts_stmt_get_email(cts_stmt stmt, cts_email *result, int start_cnt)
+{
+       char *temp;
+
+       result->id = cts_stmt_get_int(stmt, start_cnt++);
+       result->type = cts_stmt_get_int(stmt, start_cnt++);
+       temp = cts_stmt_get_text(stmt, start_cnt++);
+       result->email_addr = SAFE_STRDUP(temp);
+
+       return start_cnt;
+}
+
+int cts_stmt_get_name(cts_stmt stmt, cts_name *result, int start_cnt)
+{
+       char *temp;
+
+       result->id = cts_stmt_get_int(stmt, start_cnt++);
+       result->lang_type = cts_stmt_get_int(stmt, start_cnt++);
+       temp = cts_stmt_get_text(stmt, start_cnt++);
+       result->first = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, start_cnt++);
+       result->last = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, start_cnt++);
+       result->addition = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, start_cnt++);
+       result->display = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, start_cnt++);
+       result->prefix = SAFE_STRDUP(temp);
+       temp = cts_stmt_get_text(stmt, start_cnt++);
+       result->suffix = SAFE_STRDUP(temp);
+
+       return CTS_SUCCESS;
+}
+
diff --git a/src/cts-sqlite.h b/src/cts-sqlite.h
new file mode 100755 (executable)
index 0000000..044a3d4
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_SQLITE_H__
+#define __CTS_SQLITE_H__
+
+#include <sqlite3.h>
+#include "cts-struct.h"
+
+#define CTS_SQL_MAX_LEN   2048 //normal string length
+#define CTS_SQL_MIN_LEN  1024 //short sql string length
+
+typedef sqlite3_stmt* cts_stmt;
+
+//////////////////// iterator ////////////////////
+
+int cts_db_open(void);
+int cts_db_close(void);
+int cts_db_change();
+int cts_db_get_last_insert_id(void);
+int cts_db_get_next_id(const char *table);
+
+int cts_query_get_first_int_result(const char *query);
+int cts_query_exec(char *query);
+cts_stmt cts_query_prepare(char *query);
+
+int cts_stmt_step(cts_stmt stmt);
+void cts_stmt_reset(cts_stmt stmt);
+void cts_stmt_finalize(cts_stmt stmt);
+
+int cts_stmt_get_first_int_result(cts_stmt stmt);
+
+static inline int cts_stmt_bind_int(cts_stmt stmt, int pos, int num) {
+       return sqlite3_bind_int(stmt, pos, num);
+}
+static inline int cts_stmt_bind_text(cts_stmt stmt, int pos, const char *str) {
+       return sqlite3_bind_text(stmt, pos, str, strlen(str), SQLITE_STATIC);
+}
+static inline int cts_stmt_bind_copy_text(cts_stmt stmt, int pos,
+               const char *str, int strlen){
+       return sqlite3_bind_text(stmt, pos, str, strlen, SQLITE_TRANSIENT);
+}
+
+int cts_stmt_bind_copy_text(cts_stmt stmt, int pos, const char *str, int strlen);
+
+
+int cts_stmt_bind_name(cts_stmt stmt, int start_cnt, cts_name *name_struct);
+int cts_stmt_bind_postal(cts_stmt stmt, int start_cnt, cts_postal *postal_struct);
+int cts_stmt_bind_company(cts_stmt stmt, int start_cnt, cts_company *company_struct);
+int cts_stmt_bind_web(cts_stmt stmt, int start_cnt, cts_web *web_struct);
+int cts_stmt_bind_messenger(cts_stmt stmt, int start_cnt, cts_messenger *im_struct);
+int cts_stmt_bind_event(cts_stmt stmt, int start_cnt, cts_event *event_struct);
+int cts_stmt_bind_extend(cts_stmt stmt, int start_cnt, cts_extend *extend_struct);
+
+static inline double cts_stmt_get_dbl(cts_stmt stmt, int pos) {
+       return sqlite3_column_double(stmt, pos);
+}
+static inline int cts_stmt_get_int(cts_stmt stmt, int pos) {
+       return sqlite3_column_int(stmt, pos);
+}
+static inline char* cts_stmt_get_text(cts_stmt stmt, int pos) {
+       return (char *)sqlite3_column_text(stmt, pos);
+}
+
+int cts_stmt_get_addressbook(cts_stmt stmt, cts_addrbook *ab);
+int cts_stmt_get_number(cts_stmt stmt, cts_number *result, int start_cnt);
+int cts_stmt_get_email(cts_stmt stmt, cts_email *result, int start_cnt);
+int cts_stmt_get_name(cts_stmt stmt, cts_name *result, int start_cnt);
+
+
+#endif //__CTS_SQLITE_H__
+
diff --git a/src/cts-struct-ext.c b/src/cts-struct-ext.c
new file mode 100755 (executable)
index 0000000..79032cb
--- /dev/null
@@ -0,0 +1,745 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "cts-internal.h"
+#include "cts-utils.h"
+#include "cts-struct.h"
+#include "cts-struct-ext.h"
+
+#define CTS_VCARD_MOVE_TO(orig, src, check) \
+       do{ \
+               if (NULL == orig && NULL != src) { \
+                       orig = src; \
+                       check = true; \
+                       src = NULL; \
+               } \
+       }while(false)
+
+static inline int cts_merge_vcard_base(cts_ct_base *orig, cts_ct_base *addition)
+{
+       int ret;
+       char dest[CTS_IMG_PATH_SIZE_MAX];
+
+       retvm_if(NULL == addition, CTS_ERR_ARG_INVALID, "Invalid addition(%p)", addition);
+
+       if (NULL == orig->img_path) {
+               if (orig->id && addition->img_path) {
+                       ret = snprintf(dest, sizeof(dest), "%s/%d-%d.", CTS_IMAGE_LOCATION,
+                                       orig->id, CTS_IMG_NORMAL);
+                       if (0 != strncmp(dest, addition->img_path, ret)) {
+                               orig->img_path = addition->img_path;
+                               orig->img_changed = true;
+                               addition->img_path = NULL;
+                       }
+               } else {
+                       orig->img_path = addition->img_path;
+                       orig->img_changed = true;
+                       addition->img_path = NULL;
+               }
+       }
+
+       if (NULL == orig->full_img_path) {
+               if (orig->id && addition->full_img_path) {
+                       ret = snprintf(dest, sizeof(dest), "%s/%d-%d.", CTS_IMAGE_LOCATION,
+                                       orig->id, CTS_IMG_FULL);
+                       if (0 != strncmp(dest, addition->full_img_path, ret)) {
+                               orig->full_img_path = addition->full_img_path;
+                               orig->full_img_changed = true;
+                               addition->full_img_path = NULL;
+                       }
+               } else {
+                       orig->full_img_path = addition->full_img_path;
+                       orig->full_img_changed = true;
+                       addition->full_img_path = NULL;
+               }
+       }
+
+       CTS_VCARD_MOVE_TO(orig->uid, addition->uid, orig->uid_changed);
+       CTS_VCARD_MOVE_TO(orig->note, addition->note, orig->note_changed);
+       CTS_VCARD_MOVE_TO(orig->ringtone_path, addition->ringtone_path, orig->ringtone_changed);
+       if (NULL == orig->vcard_img_path) {
+               orig->vcard_img_path = addition->vcard_img_path;
+               addition->vcard_img_path = NULL;
+       }
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_merge_vcard_name(cts_name *orig, cts_name *addition)
+{
+       retvm_if(NULL == addition, CTS_ERR_ARG_INVALID, "Invalid addition(%p)", addition);
+
+       if (NULL == orig->first && NULL == orig->last) {
+               CTS_VCARD_MOVE_TO(orig->first, addition->first, orig->is_changed);
+               CTS_VCARD_MOVE_TO(orig->last, addition->last, orig->is_changed);
+       }
+       CTS_VCARD_MOVE_TO(orig->addition, addition->addition, orig->is_changed);
+       CTS_VCARD_MOVE_TO(orig->display, addition->display, orig->is_changed);
+       CTS_VCARD_MOVE_TO(orig->prefix, addition->prefix, orig->is_changed);
+       CTS_VCARD_MOVE_TO(orig->suffix, addition->suffix, orig->is_changed);
+
+       return CTS_SUCCESS;
+}
+
+static inline GSList* cts_merge_vcard_numbers(GSList *orig, GSList *addition)
+{
+       GSList *i, *j;
+       for (i=addition;i;i=i->next) {
+               cts_number *addition = i->data;
+
+               if (NULL == addition->number) continue;
+
+               for (j=orig;j;j=j->next) {
+                       cts_number *org = j->data;
+                       if (org->deleted) continue;
+                       if (addition->number && org->number
+                                       && 0 == strcmp(addition->number, org->number))
+                               break;
+               }
+               if (NULL == j) {
+                       orig = g_slist_append(orig, addition);
+                       i->data = NULL;
+               }
+       }
+
+       return orig;
+}
+
+static inline GSList* cts_merge_vcard_emails(GSList *orig, GSList *addition)
+{
+       GSList *i, *j;
+       for (i=addition;i;i=i->next) {
+               cts_email *addition = i->data;
+
+               if (NULL == addition->email_addr) continue;
+
+               for (j=orig;j;j=j->next) {
+                       cts_email *org = j->data;
+                       if (org->deleted) continue;
+                       if (addition->email_addr && org->email_addr
+                                       && 0 == strcmp(addition->email_addr, org->email_addr))
+                               break;
+               }
+               if (NULL == j) {
+                       orig = g_slist_append(orig, addition);
+                       i->data = NULL;
+               }
+       }
+
+       return orig;
+}
+
+static inline GSList* cts_merge_vcard_events(GSList *orig, GSList *addition)
+{
+       GSList *i, *j;
+       for (i=addition;i;i=i->next) {
+               cts_event *addition = i->data;
+               for (j=orig;j;j=j->next) {
+                       cts_event *org = j->data;
+                       if (org->deleted) continue;
+                       if (addition->date == org->date)
+                               break;
+               }
+               if (NULL == j) {
+                       orig = g_slist_append(orig, addition);
+                       i->data = NULL;
+               }
+       }
+
+       return orig;
+}
+
+static inline GSList* cts_merge_vcard_postals(GSList *orig, GSList *addition)
+{
+       GSList *i, *j;
+       for (i=addition;i;i=i->next) {
+               cts_postal *addition = i->data;
+               for (j=orig;j;j=j->next) {
+                       cts_postal *org = j->data;
+                       if (org->deleted) continue;
+                       char *s1, *s2;
+                       s1 = addition->pobox;
+                       s2 = org->pobox;
+                       if (s1 == s2 || (s1 && s2 && 0 == strcmp(s1, s2))) {
+                               s1 = addition->postalcode;
+                               s2 = org->postalcode;
+                               if (s1 == s2 || (s1 && s2 && 0 == strcmp(s1, s2))) {
+                                       s1 = addition->region;
+                                       s2 = org->region;
+                                       if (s1 == s2 || (s1 && s2 && 0 == strcmp(s1, s2))) {
+                                               s1 = addition->locality;
+                                               s2 = org->locality;
+                                               if (s1 == s2 || (s1 && s2 && 0 == strcmp(s1, s2))) {
+                                                       s1 = addition->street;
+                                                       s2 = org->street;
+                                                       if (s1 == s2 || (s1 && s2 && 0 == strcmp(s1, s2))) {
+                                                               s1 = addition->extended;
+                                                               s2 = org->extended;
+                                                               if (s1 == s2 || (s1 && s2 && 0 == strcmp(s1, s2))) {
+                                                                       s1 = addition->country;
+                                                                       s2 = org->country;
+                                                                       if (s1 == s2 || (s1 && s2 && 0 == strcmp(s1, s2))) {
+                                                                               break;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+               if (NULL == j) {
+                       orig = g_slist_append(orig, addition);
+                       i->data = NULL;
+               }
+       }
+
+       return orig;
+}
+
+static inline GSList* cts_merge_vcard_webs(GSList *orig, GSList *addition)
+{
+       GSList *i, *j;
+       for (i=addition;i;i=i->next) {
+               cts_web *addition = i->data;
+
+               if (NULL == addition->url) continue;
+
+               for (j=orig;j;j=j->next) {
+                       cts_web *org = j->data;
+                       if (org->deleted) continue;
+                       if (addition->url && org->url
+                                       && 0 == strcmp(addition->url, org->url))
+                               break;
+               }
+               if (NULL == j) {
+                       orig = g_slist_append(orig, addition);
+                       i->data = NULL;
+               }
+       }
+
+       return orig;
+}
+
+static inline GSList* cts_merge_vcard_nicknames(GSList *orig, GSList *addition)
+{
+       GSList *i, *j;
+       for (i=addition;i;i=i->next) {
+               cts_nickname *addition = i->data;
+
+               if (NULL == addition->nick) continue;
+
+               for (j=orig;j;j=j->next) {
+                       cts_nickname *org = j->data;
+                       if (org->deleted) continue;
+                       if (addition->nick && org->nick
+                                       && 0 == strcmp(addition->nick, org->nick))
+                               break;
+               }
+               if (NULL == j) {
+                       orig = g_slist_append(orig, addition);
+                       i->data = NULL;
+               }
+       }
+
+       return orig;
+}
+
+static inline GSList* cts_merge_vcard_extends(GSList *orig, GSList *addition)
+{
+       GSList *d, *t;
+       cts_extend *orig_val, *addition_val;
+
+       for (d=addition;d;d=d->next) {
+               addition_val = d->data;
+
+               for (t=orig;t;t=t->next) {
+                       orig_val = t->data;
+                       if (orig_val->deleted) continue;
+                       if (addition_val->type == orig_val->type)
+                               break;
+               }
+               if (NULL == t) {
+                       orig = g_slist_append(orig, addition_val);
+                       d->data = NULL;
+               }
+       }
+
+       return orig;
+}
+
+static inline int cts_merge_vcard_company(cts_company *orig, cts_company *addition)
+{
+       bool temp;
+
+       retvm_if(NULL == addition, CTS_ERR_ARG_INVALID, "Invalid addition(%p)", addition);
+
+       CTS_VCARD_MOVE_TO(orig->name, addition->name, temp);
+       CTS_VCARD_MOVE_TO(orig->department, addition->department, temp);
+       CTS_VCARD_MOVE_TO(orig->jot_title, addition->jot_title, temp);
+       CTS_VCARD_MOVE_TO(orig->role, addition->role, temp);
+       CTS_VCARD_MOVE_TO(orig->assistant_name, addition->assistant_name, temp);
+
+       return CTS_SUCCESS;
+}
+
+static inline GSList* cts_merge_vcard_grouprel(GSList *orig, GSList *addition)
+{
+       GSList *i, *j;
+       for (i=addition;i;i=i->next) {
+               cts_group *addition = i->data;
+
+               if (0 == addition->id) continue;
+
+               for (j=orig;j;j=j->next) {
+                       cts_group *org = j->data;
+                       if (org->deleted) continue;
+                       if (addition->id == org->id)
+                               break;
+               }
+               if (NULL == j) {
+                       orig = g_slist_append(orig, addition);
+                       i->data = NULL;
+               }
+       }
+
+       return orig;
+}
+
+API int contacts_svc_struct_merge(CTSstruct *s1, CTSstruct *s2)
+{
+       contact_t *orig, *addition;
+
+       retv_if(NULL == s1, CTS_ERR_ARG_NULL);
+       retv_if(NULL == s2, CTS_ERR_ARG_NULL);
+
+       orig = (contact_t *)s1;
+       addition = (contact_t *)s2;
+
+       if (orig->base) {
+               cts_merge_vcard_base(orig->base, addition->base);
+       } else {
+               orig->base = addition->base;
+               addition->base = NULL;
+       }
+
+       if (orig->name) {
+               cts_merge_vcard_name(orig->name, addition->name);
+       } else {
+               orig->name = addition->name;
+               addition->name = NULL;
+       }
+
+       if (orig->numbers) {
+               orig->numbers =
+                       cts_merge_vcard_numbers(orig->numbers, addition->numbers);
+       } else {
+               orig->numbers = addition->numbers;
+               addition->numbers = NULL;
+       }
+
+       if (orig->emails) {
+               orig->emails =
+                       cts_merge_vcard_emails(orig->emails, addition->emails);
+       } else {
+               orig->emails = addition->emails;
+               addition->emails = NULL;
+       }
+       //orig->grouprelations does not support.
+
+       if (orig->events) {
+               orig->events =
+                       cts_merge_vcard_events(orig->events, addition->events);
+       } else {
+               orig->events = addition->events;
+               addition->events = NULL;
+       }
+       //orig->messengers does not support.
+
+       if (orig->postal_addrs) {
+               orig->postal_addrs =
+                       cts_merge_vcard_postals(orig->postal_addrs, addition->postal_addrs);
+       } else {
+               orig->postal_addrs = addition->postal_addrs;
+               addition->postal_addrs = NULL;
+       }
+
+       if (orig->web_addrs) {
+               orig->web_addrs =
+                       cts_merge_vcard_webs(orig->web_addrs, addition->web_addrs);
+       } else {
+               orig->web_addrs = addition->web_addrs;
+               addition->web_addrs = NULL;
+       }
+
+       if (orig->nicknames) {
+               orig->nicknames =
+                       cts_merge_vcard_nicknames(orig->nicknames, addition->nicknames);
+       } else {
+               orig->nicknames = addition->nicknames;
+               addition->nicknames = NULL;
+       }
+
+       if (orig->company) {
+               cts_merge_vcard_company(orig->company, addition->company);
+       } else {
+               orig->company = addition->company;
+               addition->company = NULL;
+       }
+
+       if (orig->grouprelations) {
+               cts_merge_vcard_grouprel(orig->grouprelations, addition->grouprelations);
+       } else {
+               orig->grouprelations = addition->grouprelations;
+               addition->grouprelations = NULL;
+       }
+
+       if (orig->extended_values) {
+               orig->extended_values =
+                       cts_merge_vcard_extends(orig->extended_values, addition->extended_values);
+       } else {
+               orig->extended_values = addition->extended_values;
+               addition->extended_values = NULL;
+       }
+
+       return CTS_SUCCESS;
+}
+
+static inline cts_ct_base* cts_struct_dup_base(const cts_ct_base *src)
+{
+       cts_ct_base *result = NULL;
+       if (src) {
+               result = calloc(1, sizeof(cts_ct_base));
+               retvm_if(NULL == result, NULL, "calloc() Failed");
+
+               memcpy(result, src, sizeof(cts_ct_base));
+
+               if (src->uid)
+                       result->uid = strdup(src->uid);
+               if (src->img_path)
+                       result->img_path = strdup(src->img_path);
+               if (src->full_img_path)
+                       result->full_img_path = strdup(src->full_img_path);
+               if (src->ringtone_path)
+                       result->ringtone_path = strdup(src->ringtone_path);
+               if (src->note)
+                       result->note = strdup(src->note);
+               if (src->vcard_img_path)
+                       result->vcard_img_path = strdup(src->vcard_img_path);
+       }
+
+       return result;
+}
+
+static inline cts_name* cts_struct_dup_name(const cts_name *src)
+{
+       cts_name *result = NULL;
+       if (src) {
+               result = calloc(1, sizeof(cts_name));
+               retvm_if(NULL == result, NULL, "calloc() Failed");
+
+               memcpy(result, src, sizeof(cts_name));
+
+               if (src->first)
+                       result->first = strdup(src->first);
+               if (src->last)
+                       result->last = strdup(src->last);
+               if (src->addition)
+                       result->addition = strdup(src->addition);
+               if (src->display)
+                       result->display = strdup(src->display);
+               if (src->prefix)
+                       result->prefix = strdup(src->prefix);
+               if (src->suffix)
+                       result->suffix = strdup(src->suffix);
+       }
+
+       return result;
+}
+
+static inline cts_number* cts_struct_dup_number(const cts_number *src)
+{
+       cts_number *result = NULL;
+       if (src) {
+               result = calloc(1, sizeof(cts_number));
+               retvm_if(NULL == result, NULL, "calloc() Failed");
+
+               memcpy(result, src, sizeof(cts_number));
+
+               if (src->number)
+                       result->number = strdup(src->number);
+       }
+
+       return result;
+}
+
+static inline cts_email* cts_struct_dup_email(const cts_email *src)
+{
+       cts_email *result = NULL;
+       if (src) {
+               result = calloc(1, sizeof(cts_email));
+               retvm_if(NULL == result, NULL, "calloc() Failed");
+
+               memcpy(result, src, sizeof(cts_email));
+
+               if (src->email_addr)
+                       result->email_addr = strdup(src->email_addr);
+       }
+
+       return result;
+}
+
+static inline cts_web* cts_struct_dup_web(const cts_web *src)
+{
+       cts_web *result = NULL;
+       if (src) {
+               result = calloc(1, sizeof(cts_web));
+               retvm_if(NULL == result, NULL, "calloc() Failed");
+
+               memcpy(result, src, sizeof(cts_web));
+
+               if (src->url)
+                       result->url = strdup(src->url);
+       }
+
+       return result;
+}
+
+static inline cts_postal* cts_struct_dup_postal(const cts_postal *src)
+{
+       cts_postal *result = NULL;
+       if (src) {
+               result = calloc(1, sizeof(cts_postal));
+               retvm_if(NULL == result, NULL, "calloc() Failed");
+
+               memcpy(result, src, sizeof(cts_postal));
+
+               if (src->pobox)
+                       result->pobox = strdup(src->pobox);
+               if (src->postalcode)
+                       result->postalcode = strdup(src->postalcode);
+               if (src->region)
+                       result->region = strdup(src->region);
+               if (src->locality)
+                       result->locality = strdup(src->locality);
+               if (src->street)
+                       result->street = strdup(src->street);
+               if (src->extended)
+                       result->extended = strdup(src->extended);
+               if (src->country)
+                       result->country = strdup(src->country);
+       }
+
+       return result;
+}
+
+static inline cts_event* cts_struct_dup_event(const cts_event *src)
+{
+       cts_event *result = NULL;
+       if (src) {
+               result = calloc(1, sizeof(cts_event));
+               retvm_if(NULL == result, NULL, "calloc() Failed");
+
+               memcpy(result, src, sizeof(cts_event));
+       }
+
+       return result;
+}
+
+static inline cts_messenger* cts_struct_dup_messenger(const cts_messenger *src)
+{
+       cts_messenger *result = NULL;
+       if (src) {
+               result = calloc(1, sizeof(cts_messenger));
+               retvm_if(NULL == result, NULL, "calloc() Failed");
+
+               memcpy(result, src, sizeof(cts_messenger));
+
+               if (src->im_id)
+                       result->im_id = strdup(src->im_id);
+       }
+
+       return result;
+}
+
+static inline cts_group* cts_struct_dup_grouprel(const cts_group *src)
+{
+       cts_group *result = NULL;
+       if (src) {
+               result = calloc(1, sizeof(cts_group));
+               retvm_if(NULL == result, NULL, "calloc() Failed");
+
+               memcpy(result, src, sizeof(cts_group));
+
+               if (src->name)
+                       result->name = strdup(src->name);
+               if (src->ringtone_path)
+                       result->ringtone_path = strdup(src->ringtone_path);
+       }
+
+       return result;
+}
+
+static inline cts_extend* cts_struct_dup_extend(const cts_extend *src)
+{
+       cts_extend *result = NULL;
+       if (src) {
+               result = calloc(1, sizeof(cts_extend));
+               retvm_if(NULL == result, NULL, "calloc() Failed");
+
+               memcpy(result, src, sizeof(cts_extend));
+
+               if (src->data2)
+                       result->data2 = strdup(src->data2);
+               if (src->data3)
+                       result->data3 = strdup(src->data3);
+               if (src->data4)
+                       result->data4 = strdup(src->data4);
+               if (src->data5)
+                       result->data5 = strdup(src->data5);
+               if (src->data6)
+                       result->data6 = strdup(src->data6);
+               if (src->data7)
+                       result->data7 = strdup(src->data7);
+               if (src->data8)
+                       result->data8 = strdup(src->data8);
+               if (src->data9)
+                       result->data9 = strdup(src->data9);
+               if (src->data10)
+                       result->data10 = strdup(src->data10);
+       }
+
+       return result;
+}
+
+static inline cts_nickname* cts_struct_dup_nick(const cts_nickname *src)
+{
+       cts_nickname *result = NULL;
+       if (src) {
+               result = calloc(1, sizeof(cts_nickname));
+               retvm_if(NULL == result, NULL, "calloc() Failed");
+
+               memcpy(result, src, sizeof(cts_nickname));
+
+               if (src->nick)
+                       result->nick = strdup(src->nick);
+       }
+
+       return result;
+}
+
+static inline GSList* cts_struct_dup_list(int type, GSList *src)
+{
+       GSList *cur, *result = NULL;
+       if (src) {
+               result = g_slist_copy(src);
+
+               for (cur=result;cur;cur=cur->next) {
+                       switch (type) {
+                       case CTS_VALUE_NUMBER:
+                               cur->data = cts_struct_dup_number(cur->data);
+                               break;
+                       case CTS_VALUE_EMAIL:
+                               cur->data = cts_struct_dup_email(cur->data);
+                               break;
+                       case CTS_VALUE_WEB:
+                               cur->data = cts_struct_dup_web(cur->data);
+                               break;
+                       case CTS_VALUE_POSTAL:
+                               cur->data = cts_struct_dup_postal(cur->data);
+                               break;
+                       case CTS_VALUE_EVENT:
+                               cur->data = cts_struct_dup_event(cur->data);
+                               break;
+                       case CTS_VALUE_MESSENGER:
+                               cur->data = cts_struct_dup_messenger(cur->data);
+                               break;
+                       case CTS_VALUE_GROUP_RELATION:
+                               cur->data = cts_struct_dup_grouprel(cur->data);
+                               break;
+                       case CTS_VALUE_EXTEND:
+                               cur->data = cts_struct_dup_extend(cur->data);
+                               break;
+                       case CTS_VALUE_NICKNAME:
+                               cur->data = cts_struct_dup_nick(cur->data);
+                               break;
+                       default:
+                               ERR("invalid type(%d)", type);
+                               break;
+                       }
+               }
+       }
+
+       return result;
+}
+
+static inline cts_company* cts_struct_dup_company(const cts_company *src)
+{
+       cts_company *result = NULL;
+       if (src) {
+               result = calloc(1, sizeof(cts_company));
+               retvm_if(NULL == result, NULL, "calloc() Failed");
+
+               memcpy(result, src, sizeof(cts_company));
+
+               if (src->name)
+                       result->name = strdup(src->name);
+               if (src->department)
+                       result->department = strdup(src->department);
+               if (src->jot_title)
+                       result->jot_title = strdup(src->jot_title);
+               if (src->role)
+                       result->role = strdup(src->role);
+               if (src->assistant_name)
+                       result->assistant_name = strdup(src->assistant_name);
+       }
+
+       return result;
+}
+
+API CTSstruct* contacts_svc_struct_duplicate(const CTSstruct *contact)
+{
+       contact_t *src, *result = NULL;
+
+       retvm_if(NULL == contact, NULL, "contact is NULL");
+
+       src = (contact_t *)contact;
+       result = (contact_t *)contacts_svc_struct_new(CTS_STRUCT_CONTACT);
+       retvm_if(NULL == result, NULL, "contacts_svc_struct_new() Failed");
+
+       result->base = cts_struct_dup_base(src->base);
+       result->name = cts_struct_dup_name(src->name);
+       result->numbers = cts_struct_dup_list(CTS_VALUE_NUMBER, src->numbers);
+       result->emails = cts_struct_dup_list(CTS_VALUE_EMAIL, src->emails);
+       result->web_addrs = cts_struct_dup_list(CTS_VALUE_WEB, src->web_addrs);
+       result->postal_addrs = cts_struct_dup_list(CTS_VALUE_POSTAL, src->postal_addrs);
+       result->events = cts_struct_dup_list(CTS_VALUE_EVENT, src->events);
+       result->messengers = cts_struct_dup_list(CTS_VALUE_MESSENGER, src->messengers);
+       result->grouprelations = cts_struct_dup_list(CTS_VALUE_GROUP_RELATION, src->grouprelations);
+       result->company = cts_struct_dup_company(src->company);
+       result->extended_values = cts_struct_dup_list(CTS_VALUE_EXTEND, src->extended_values);
+       result->nicknames = cts_struct_dup_list(CTS_VALUE_NICKNAME, src->nicknames);
+
+       result->default_num = src->default_num;
+       result->default_email = src->default_email;
+
+       return (CTSstruct *)result;
+}
+
diff --git a/src/cts-struct-ext.h b/src/cts-struct-ext.h
new file mode 100755 (executable)
index 0000000..88c373c
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_STRUCT_EXT_H__
+#define __CTS_STRUCT_EXT_H__
+
+//<!--
+
+/**
+ * This function merges two contact. #s2 merges into #s1.
+ * Free #s2 immediately, regardless of success.
+ * #s2 must not be used after calling this function.
+ * If single-value field(_VALUE suffix) is conflict, s2 value is ignored.
+ * The case of multi-value field(_LIST suffix), s2 list will be append to s1 list.
+ *
+ *
+ * @param[in] s1 The base contact
+ * @param[in] s2 The contact which is added to #s1.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_struct_merge(CTSstruct *s1, CTSstruct *s2);
+
+/**
+ * duplicate a contact struct.
+ *
+ * @param[in] contact a contact struct(#CTSstruct)
+ * @return a pointer to a new duplicated contact struct on success, NULL on error
+ */
+CTSstruct* contacts_svc_struct_duplicate(const CTSstruct *contact);
+
+//-->
+
+#endif //__CTS_STRUCT_EXT_H__
+
diff --git a/src/cts-struct.c b/src/cts-struct.c
new file mode 100755 (executable)
index 0000000..e701f2c
--- /dev/null
@@ -0,0 +1,2927 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <unistd.h>
+#include <errno.h>
+
+#include "cts-internal.h"
+#include "cts-list.h"
+#include "cts-utils.h"
+
+static contact_list *contact_list_mempool=NULL;
+static plog_list *plog_list_mempool=NULL;
+static change_list *change_list_mempool=NULL;
+static numtype_list *numtype_list_mempool=NULL;
+static shortcut_list *favorite_list_mempool=NULL;
+static cts_group *group_list_mempool=NULL;
+static cts_addrbook *addrbook_list_mempool=NULL;
+static sdn_list *sdn_list_mempool=NULL;
+
+API CTSstruct* contacts_svc_struct_new(cts_struct_type type)
+{
+       CTSstruct* ret_val;
+       switch (type)
+       {
+       case CTS_STRUCT_CONTACT:
+               ret_val = (CTSstruct*)calloc(1, sizeof(contact_t));
+               if (ret_val) ret_val->s_type = CTS_STRUCT_CONTACT;
+               return ret_val;
+       default:
+               ERR("your type is Not supported");
+               return NULL;
+       }
+}
+
+static void cts_number_free(gpointer data, gpointer user_data)
+{
+       if (NULL == data || !((cts_number*)data)->embedded)
+               return;
+
+       free(((cts_number*)data)->number);
+       free(((cts_number*)data)->added_type);
+       free(data);
+}
+static void cts_email_free(gpointer data, gpointer user_data)
+{
+       if (NULL == data || !((cts_email*)data)->embedded)
+               return;
+
+       free(((cts_email*)data)->email_addr);
+       free(data);
+}
+static void cts_group_free(gpointer data, gpointer user_data)
+{
+       cts_group* data0 = (cts_group*)data;
+
+       if (NULL == data || !data0->embedded)
+               return;
+
+       free(data0->name);
+       free(data0->ringtone_path);
+       free(data0->vcard_group);
+       free(data);
+}
+static void cts_event_free(gpointer data, gpointer user_data)
+{
+       if (NULL == data || !((cts_event*)data)->embedded)
+               return;
+
+       free(data);
+}
+static void cts_messenger_free(gpointer data, gpointer user_data)
+{
+       if (NULL == data || !((cts_messenger*)data)->embedded)
+               return;
+
+       free(((cts_messenger*)data)->im_id);
+       free(data);
+}
+static void cts_postal_free(gpointer data, gpointer user_data)
+{
+       cts_postal *data0 = (cts_postal *)data;
+
+       if (NULL == data0 || !data0->embedded)
+               return;
+
+       free(data0->pobox);
+       free(data0->postalcode);
+       free(data0->region);
+       free(data0->locality);
+       free(data0->street);
+       free(data0->extended);
+       free(data0->country);
+       free(data);
+}
+static void cts_web_free(gpointer data, gpointer user_data)
+{
+       if (NULL == data || !((cts_web*)data)->embedded)
+               return;
+
+       free(((cts_web*)data)->url);
+       free(data);
+}
+static void cts_nickname_free(gpointer data, gpointer user_data)
+{
+       if (NULL == data || !((cts_nickname*)data)->embedded)
+               return;
+
+       free(((cts_nickname*)data)->nick);
+       free(data);
+}
+
+static void cts_extend_free(gpointer data, gpointer user_data)
+{
+       cts_extend *data0 = (cts_extend *)data;
+       if (NULL == data0 || !data0->embedded)
+               return;
+
+       free(data0->data2);
+       free(data0->data3);
+       free(data0->data4);
+       free(data0->data5);
+       free(data0->data6);
+       free(data0->data7);
+       free(data0->data8);
+       free(data0->data9);
+       free(data0->data10);
+       free(data);
+}
+
+static inline void cts_name_free(cts_name *name)
+{
+       if (!name->embedded)
+               return;
+
+       free(name->first);
+       free(name->last);
+       free(name->addition);
+       free(name->display);
+       free(name->prefix);
+       free(name->suffix);
+       free(name);
+}
+
+static inline void cts_company_free(cts_company *company)
+{
+       if (!company->embedded)
+               return;
+
+       free(company->name);
+       free(company->department);
+       free(company->jot_title);
+       free(company->role);
+       free(company->assistant_name);
+       free(company);
+}
+
+static inline void cts_contact_free(contact_t *contact)
+{
+       if (contact->base && contact->base->embedded) {
+               free(contact->base->uid);
+               free(contact->base->img_path);
+               free(contact->base->full_img_path);
+               free(contact->base->ringtone_path);
+               free(contact->base->note);
+
+               if (contact->base->vcard_img_path) {
+                       unlink(contact->base->vcard_img_path);
+                       free(contact->base->vcard_img_path);
+               }
+
+               free(contact->base);
+       }
+
+       if (contact->name)
+               cts_name_free(contact->name);
+
+       if (contact->company)
+               cts_company_free(contact->company);
+
+       if (contact->numbers) {
+               g_slist_foreach(contact->numbers, cts_number_free, NULL);
+               g_slist_free(contact->numbers);
+       }
+
+       if (contact->emails) {
+               g_slist_foreach(contact->emails, cts_email_free, NULL);
+               g_slist_free(contact->emails);
+       }
+
+       if (contact->grouprelations) {
+               g_slist_foreach(contact->grouprelations, cts_group_free, NULL);
+               g_slist_free(contact->grouprelations);
+       }
+
+       if (contact->events) {
+               g_slist_foreach(contact->events, cts_event_free, NULL);
+               g_slist_free(contact->events);
+       }
+
+       if (contact->messengers) {
+               g_slist_foreach(contact->messengers, cts_messenger_free, NULL);
+               g_slist_free(contact->messengers);
+       }
+
+       if (contact->postal_addrs) {
+               g_slist_foreach(contact->postal_addrs, cts_postal_free, NULL);
+               g_slist_free(contact->postal_addrs);
+       }
+
+       if (contact->web_addrs) {
+               g_slist_foreach(contact->web_addrs, cts_web_free, NULL);
+               g_slist_free(contact->web_addrs);
+       }
+
+       if (contact->nicknames) {
+               g_slist_foreach(contact->nicknames, cts_nickname_free, NULL);
+               g_slist_free(contact->nicknames);
+       }
+
+       if (contact->extended_values) {
+               g_slist_foreach(contact->extended_values, cts_extend_free, NULL);
+               g_slist_free(contact->extended_values);
+       }
+}
+
+API int contacts_svc_struct_free(CTSstruct* structure)
+{
+       retv_if(NULL == structure, CTS_ERR_ARG_NULL);
+
+       switch (structure->s_type)
+       {
+       case CTS_STRUCT_CONTACT:
+               cts_contact_free((contact_t *)structure);
+               free(structure);
+               break;
+       default:
+               ERR("The structure type(%d) is Not valid", structure->s_type);
+               return CTS_ERR_ARG_INVALID;
+       }
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_struct_get_list(CTSstruct *contact,
+               cts_struct_field field, GSList** retlist)
+{
+       contact_t *record = (contact_t *)contact;
+
+       retv_if(NULL == contact, CTS_ERR_ARG_NULL);
+       retv_if(NULL == retlist, CTS_ERR_ARG_NULL);
+       retvm_if(CTS_STRUCT_CONTACT != contact->s_type, CTS_ERR_ARG_INVALID,
+                       "The contact(%d) must be type of CTS_STRUCT_CONTACT.", contact->s_type);
+
+       switch (field)
+       {
+       case CTS_CF_NUMBER_LIST:
+               *retlist = record->numbers;
+               break;
+       case CTS_CF_EMAIL_LIST:
+               *retlist = record->emails;
+               break;
+       case CTS_CF_GROUPREL_LIST:
+               *retlist = record->grouprelations;
+               break;
+       case CTS_CF_EVENT_LIST:
+               *retlist = record->events;
+               break;
+       case CTS_CF_MESSENGER_LIST:
+               *retlist = record->messengers;
+               break;
+       case CTS_CF_POSTAL_ADDR_LIST:
+               *retlist = record->postal_addrs;
+               break;
+       case CTS_CF_WEB_ADDR_LIST:
+               *retlist = record->web_addrs;
+               break;
+       case CTS_CF_NICKNAME_LIST:
+               *retlist = record->nicknames;
+               break;
+       default:
+               ERR("The parameter(field) is invalid"
+                               "You MUST be (CTS_CF_VALUE_MAX < field < CTS_CF_FIELD_MAX).");
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       if (NULL == *retlist) return CTS_ERR_NO_DATA;
+
+       return CTS_SUCCESS;
+}
+
+static cts_extend* cts_extend_slist_search(int type, GSList *list)
+{
+       cts_extend *tmp_extend;
+       GSList *tmp_gslist=list;
+       while (tmp_gslist)
+       {
+               tmp_extend = tmp_gslist->data;
+               retvm_if(CTS_VALUE_EXTEND != tmp_extend->v_type, NULL,
+                               "List has other type");
+               if (tmp_extend->type == type) return tmp_extend;
+
+               tmp_gslist = tmp_gslist->next;
+       }
+       return NULL;
+}
+
+static inline int cts_contact_get_value(contact_t *contact,
+               cts_struct_field field, CTSvalue** retval)
+{
+
+       switch (field)
+       {
+       case CTS_CF_NAME_VALUE:
+               *retval = (CTSvalue *)contact->name;
+               break;
+       case CTS_CF_BASE_INFO_VALUE:
+               *retval = (CTSvalue *)contact->base;
+               break;
+       case CTS_CF_COMPANY_VALUE:
+               *retval = (CTSvalue *)contact->company;
+               break;
+       default:
+               if ((int)CTS_DATA_EXTEND_START <= field) {
+                       *retval = (CTSvalue *)cts_extend_slist_search(field,
+                                       contact->extended_values);
+                       return CTS_SUCCESS;
+               }
+               ERR("The parameter(field:%d) is not interpreted", field);
+               return CTS_ERR_ARG_INVALID;
+       }
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_struct_get_value(CTSstruct *structure,
+               cts_struct_field field, CTSvalue **retval)
+{
+       int ret;
+
+       retv_if(NULL == structure, CTS_ERR_ARG_NULL);
+       retv_if(NULL == retval, CTS_ERR_ARG_NULL);
+
+       switch (structure->s_type)
+       {
+       case CTS_STRUCT_CONTACT:
+               ret = cts_contact_get_value((contact_t *)structure, field, retval);
+               if (CTS_SUCCESS != ret)
+                       return ret;
+               break;
+       default:
+               ERR("The structure type(%d) is Not valid", structure->s_type);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       if (NULL == *retval) return CTS_ERR_NO_DATA;
+       return CTS_SUCCESS;
+}
+
+#define CTS_REMOVE_GSLIST_ITEM(type, loc) \
+       do { \
+               cts_##type##_free(tmp_##type, NULL); \
+               if (prev) { \
+                       prev->next = tmp_gslist->next; \
+                       g_slist_free_1(tmp_gslist); \
+                       tmp_gslist = prev->next; \
+               } \
+               else { \
+                       contact->loc = tmp_gslist->next; \
+                       g_slist_free_1(tmp_gslist); \
+                       tmp_gslist = contact->loc; \
+               } \
+       }while(false)
+
+static inline int cts_struct_store_num_list(contact_t *contact, GSList* list)
+{
+       cts_number *tmp_number;
+
+       GSList *new_gslist=NULL, *tmp_gslist=list, *prev=NULL;
+       if (contact->numbers && tmp_gslist == contact->numbers)
+       {
+               while (tmp_gslist)
+               {
+                       tmp_number = tmp_gslist->data;
+                       if (tmp_number)
+                       {
+                               retvm_if(CTS_VALUE_NUMBER != tmp_number->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+
+                               if (!tmp_number->id && tmp_number->deleted)
+                               {
+                                       CTS_REMOVE_GSLIST_ITEM(number, numbers);
+                                       continue;
+                               }
+
+                               if (!tmp_number->embedded)
+                               {
+                                       tmp_number->embedded = true;
+                                       tmp_number->number = SAFE_STRDUP(tmp_number->number);
+                               }
+                       }
+                       prev = tmp_gslist;
+                       tmp_gslist = tmp_gslist->next;
+               }
+       }
+       else
+       {
+               while (tmp_gslist)
+               {
+                       tmp_number = tmp_gslist->data;
+                       if (tmp_number)
+                       {
+                               retvm_if(tmp_number && CTS_VALUE_NUMBER != tmp_number->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+                               if (!tmp_number->embedded)
+                               {
+                                       tmp_number->embedded = true;
+                                       tmp_number->number = SAFE_STRDUP(tmp_number->number);
+                                       new_gslist = g_slist_append(new_gslist, tmp_number);
+                               }
+                       }
+                       tmp_gslist = tmp_gslist->next;
+               }
+               contact->numbers = g_slist_concat(contact->numbers, new_gslist);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_struct_store_email_list(contact_t *contact, GSList* list)
+{
+       cts_email *tmp_email;
+
+       GSList *new_gslist=NULL, *tmp_gslist=list, *prev=NULL;
+       if (contact->emails && tmp_gslist == contact->emails)
+       {
+               while (tmp_gslist)
+               {
+                       tmp_email = tmp_gslist->data;
+                       if (tmp_email)
+                       {
+                               retvm_if(CTS_VALUE_EMAIL != tmp_email->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+
+                               if (!tmp_email->id && tmp_email->deleted) {
+                                       CTS_REMOVE_GSLIST_ITEM(email, emails);
+                                       continue;
+                               }
+
+                               if (!tmp_email->embedded)
+                               {
+                                       tmp_email->embedded = true;
+                                       tmp_email->email_addr = SAFE_STRDUP(tmp_email->email_addr);
+                               }
+                       }
+                       prev = tmp_gslist;
+                       tmp_gslist = tmp_gslist->next;
+               }
+       }
+       else
+       {
+               while (tmp_gslist)
+               {
+                       tmp_email = tmp_gslist->data;
+                       if (tmp_email)
+                       {
+                               retvm_if(CTS_VALUE_EMAIL != tmp_email->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+                               if (!tmp_email->embedded)
+                               {
+                                       tmp_email->embedded = true;
+                                       tmp_email->email_addr = SAFE_STRDUP(tmp_email->email_addr);
+                                       new_gslist = g_slist_append(new_gslist, tmp_email);
+                               }
+                       }
+                       tmp_gslist = tmp_gslist->next;
+               }
+               contact->emails = g_slist_concat(contact->emails, new_gslist);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_struct_store_grouprel_list(contact_t *contact, GSList* list)
+{
+       cts_group *tmp_group;
+
+       GSList *new_gslist=NULL, *tmp_gslist=list, *prev=NULL;
+       if (contact->grouprelations && tmp_gslist == contact->grouprelations)
+       {
+               while (tmp_gslist)
+               {
+                       tmp_group = tmp_gslist->data;
+                       if (tmp_group)
+                       {
+                               retvm_if(CTS_VALUE_GROUP_RELATION != tmp_group->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+
+                               if (!tmp_group->name && tmp_group->deleted) {
+                                       CTS_REMOVE_GSLIST_ITEM(group, grouprelations);
+                                       continue;
+                               }
+
+                               tmp_group->embedded = true;
+                       }
+                       prev = tmp_gslist;
+                       tmp_gslist = tmp_gslist->next;
+               }
+       }
+       else
+       {
+               while (tmp_gslist)
+               {
+                       tmp_group = tmp_gslist->data;
+                       if (tmp_group)
+                       {
+                               retvm_if(CTS_VALUE_GROUP_RELATION != tmp_group->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+                               if (!tmp_group->embedded)
+                               {
+                                       tmp_group->embedded = true;
+                                       new_gslist = g_slist_append(new_gslist, tmp_group);
+                               }
+                       }
+                       tmp_gslist = tmp_gslist->next;
+               }
+               contact->grouprelations = g_slist_concat(contact->grouprelations, new_gslist);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_struct_store_event_list(contact_t *contact, GSList* list)
+{
+       cts_event *tmp_event;
+
+       GSList *new_gslist=NULL, *tmp_gslist=list, *prev=NULL;
+       if (contact->events && tmp_gslist == contact->events)
+       {
+               while (tmp_gslist)
+               {
+                       tmp_event = tmp_gslist->data;
+                       if (tmp_event)
+                       {
+                               retvm_if(CTS_VALUE_EVENT != tmp_event->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+
+                               if (!tmp_event->id && tmp_event->deleted) {
+                                       CTS_REMOVE_GSLIST_ITEM(event, events);
+                                       continue;
+                               }
+
+                               tmp_event->embedded = true;
+                       }
+                       prev = tmp_gslist;
+                       tmp_gslist = tmp_gslist->next;
+               }
+       }
+       else
+       {
+               while (tmp_gslist)
+               {
+                       tmp_event = tmp_gslist->data;
+                       if (tmp_event)
+                       {
+                               retvm_if(CTS_VALUE_EVENT != tmp_event->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+                               if (!tmp_event->embedded)
+                               {
+                                       tmp_event->embedded = true;
+                                       new_gslist = g_slist_append(new_gslist, tmp_event);
+                               }
+                       }
+                       tmp_gslist = tmp_gslist->next;
+               }
+               contact->events = g_slist_concat(contact->events, new_gslist);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_struct_store_messenger_list(contact_t *contact, GSList* list)
+{
+       cts_messenger *tmp_messenger;
+
+       GSList *new_gslist=NULL, *tmp_gslist=list, *prev=NULL;
+       if (contact->messengers && tmp_gslist == contact->messengers)
+       {
+               while (tmp_gslist)
+               {
+                       tmp_messenger = tmp_gslist->data;
+                       if (tmp_messenger)
+                       {
+                               retvm_if(CTS_VALUE_MESSENGER != tmp_messenger->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+
+                               if (!tmp_messenger->id && tmp_messenger->deleted) {
+                                       CTS_REMOVE_GSLIST_ITEM(messenger, messengers);
+                                       continue;
+                               }
+
+                               if (!tmp_messenger->embedded)
+                               {
+                                       tmp_messenger->embedded = true;
+                                       tmp_messenger->im_id = SAFE_STRDUP(tmp_messenger->im_id);
+                               }
+                       }
+                       prev = tmp_gslist;
+                       tmp_gslist = tmp_gslist->next;
+               }
+       }
+       else
+       {
+               while (tmp_gslist)
+               {
+                       tmp_messenger = tmp_gslist->data;
+                       if (tmp_messenger)
+                       {
+                               retvm_if(CTS_VALUE_MESSENGER != tmp_messenger->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+                               if (!tmp_messenger->embedded)
+                               {
+                                       tmp_messenger->embedded = true;
+                                       tmp_messenger->im_id = SAFE_STRDUP(tmp_messenger->im_id);
+                                       new_gslist = g_slist_append(new_gslist, tmp_messenger);
+                               }
+                       }
+                       tmp_gslist = tmp_gslist->next;
+               }
+               contact->messengers = g_slist_concat(contact->messengers, new_gslist);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_struct_store_postal_list(contact_t *contact, GSList* list)
+{
+       cts_postal *tmp_postal;
+
+       GSList *new_gslist=NULL, *tmp_gslist=list, *prev=NULL;
+       if (contact->postal_addrs && tmp_gslist == contact->postal_addrs)
+       {
+               while (tmp_gslist)
+               {
+                       tmp_postal = tmp_gslist->data;
+                       if (tmp_postal)
+                       {
+                               retvm_if(CTS_VALUE_POSTAL != tmp_postal->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+
+                               if (!tmp_postal->id && tmp_postal->deleted) {
+                                       CTS_REMOVE_GSLIST_ITEM(postal, postal_addrs);
+                                       continue;
+                               }
+
+                               if (!tmp_postal->embedded) {
+                                       tmp_postal->embedded = true;
+                                       tmp_postal->pobox = SAFE_STRDUP(tmp_postal->pobox);
+                                       tmp_postal->postalcode = SAFE_STRDUP(tmp_postal->postalcode);
+                                       tmp_postal->region = SAFE_STRDUP(tmp_postal->region);
+                                       tmp_postal->locality = SAFE_STRDUP(tmp_postal->locality);
+                                       tmp_postal->street = SAFE_STRDUP(tmp_postal->street);
+                                       tmp_postal->extended = SAFE_STRDUP(tmp_postal->extended);
+                                       tmp_postal->country = SAFE_STRDUP(tmp_postal->country);
+                               }
+                       }
+                       prev = tmp_gslist;
+                       tmp_gslist = tmp_gslist->next;
+               }
+       }
+       else
+       {
+               //retvm_if(NULL != contact->postal_addrs, CTS_ERR_ARG_INVALID, "New list can be stored when struct has no list");
+               while (tmp_gslist)
+               {
+                       tmp_postal = tmp_gslist->data;
+                       if (tmp_postal) {
+                               retvm_if(tmp_postal && CTS_VALUE_POSTAL != tmp_postal->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+                               if (!tmp_postal->embedded) {
+                                       tmp_postal->embedded = true;
+                                       tmp_postal->pobox = SAFE_STRDUP(tmp_postal->pobox);
+                                       tmp_postal->postalcode = SAFE_STRDUP(tmp_postal->postalcode);
+                                       tmp_postal->region = SAFE_STRDUP(tmp_postal->region);
+                                       tmp_postal->locality = SAFE_STRDUP(tmp_postal->locality);
+                                       tmp_postal->street = SAFE_STRDUP(tmp_postal->street);
+                                       tmp_postal->extended = SAFE_STRDUP(tmp_postal->extended);
+                                       tmp_postal->country = SAFE_STRDUP(tmp_postal->country);
+                                       new_gslist = g_slist_append(new_gslist, tmp_postal);
+                               }
+                       }
+                       tmp_gslist = tmp_gslist->next;
+               }
+               contact->postal_addrs = g_slist_concat(contact->postal_addrs, new_gslist);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_struct_store_web_list(contact_t *contact, GSList* list)
+{
+       cts_web *tmp_web;
+
+       GSList *new_gslist=NULL, *tmp_gslist=list, *prev=NULL;
+       if (contact->web_addrs && tmp_gslist == contact->web_addrs)
+       {
+               while (tmp_gslist)
+               {
+                       tmp_web = tmp_gslist->data;
+                       if (tmp_web)
+                       {
+                               retvm_if(CTS_VALUE_WEB != tmp_web->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+
+                               if (!tmp_web->id && tmp_web->deleted) {
+                                       CTS_REMOVE_GSLIST_ITEM(web, web_addrs);
+                                       continue;
+                               }
+
+                               if (!tmp_web->embedded) {
+                                       tmp_web->embedded = true;
+                                       tmp_web->url = SAFE_STRDUP(tmp_web->url);
+                               }
+                       }
+                       prev = tmp_gslist;
+                       tmp_gslist = tmp_gslist->next;
+               }
+       }
+       else
+       {
+               while (tmp_gslist)
+               {
+                       tmp_web = tmp_gslist->data;
+                       if (tmp_web)
+                       {
+                               retvm_if(tmp_web && CTS_VALUE_WEB != tmp_web->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+                               if (!tmp_web->embedded) {
+                                       tmp_web->embedded = true;
+                                       tmp_web->url = SAFE_STRDUP(tmp_web->url);
+                                       new_gslist = g_slist_append(new_gslist, tmp_web);
+                               }
+                       }
+                       tmp_gslist = tmp_gslist->next;
+               }
+               contact->web_addrs = g_slist_concat(contact->web_addrs, new_gslist);
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_struct_store_nickname_list(contact_t *contact, GSList* list)
+{
+       cts_nickname *tmp_nickname;
+
+       GSList *new_gslist=NULL, *tmp_gslist=list, *prev=NULL;
+       if (contact->nicknames && tmp_gslist == contact->nicknames)
+       {
+               while (tmp_gslist)
+               {
+                       tmp_nickname = tmp_gslist->data;
+                       if (tmp_nickname)
+                       {
+                               retvm_if(CTS_VALUE_NICKNAME != tmp_nickname->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+
+                               if (!tmp_nickname->id && tmp_nickname->deleted) {
+                                       CTS_REMOVE_GSLIST_ITEM(nickname, nicknames);
+                                       continue;
+                               }
+
+                               if (!tmp_nickname->embedded) {
+                                       tmp_nickname->embedded = true;
+                                       tmp_nickname->nick = SAFE_STRDUP(tmp_nickname->nick);
+                               }
+                       }
+                       prev = tmp_gslist;
+                       tmp_gslist = tmp_gslist->next;
+               }
+       }
+       else
+       {
+               //retvm_if(NULL != contact->web_addrs, CTS_ERR_ARG_INVALID, "New list can be stored when struct has no list");
+               while (tmp_gslist)
+               {
+                       tmp_nickname = tmp_gslist->data;
+                       if (tmp_nickname) {
+                               retvm_if(tmp_nickname && CTS_VALUE_NICKNAME != tmp_nickname->v_type, CTS_ERR_ARG_INVALID,
+                                               "List has other type");
+                               if (!tmp_nickname->embedded)
+                               {
+                                       tmp_nickname->embedded = true;
+                                       tmp_nickname->nick = SAFE_STRDUP(tmp_nickname->nick);
+                                       new_gslist = g_slist_append(new_gslist, tmp_nickname);
+                               }
+                       }
+                       tmp_gslist = tmp_gslist->next;
+               }
+               contact->nicknames = g_slist_concat(contact->nicknames, new_gslist);
+       }
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_struct_store_list(CTSstruct *contact,
+               cts_struct_field field, GSList *list)
+{
+       int ret;
+
+       retv_if(NULL == contact, CTS_ERR_ARG_NULL);
+       retv_if(NULL == list, CTS_ERR_ARG_NULL);
+       retvm_if(CTS_STRUCT_CONTACT != contact->s_type, CTS_ERR_ARG_INVALID,
+                       "The contact(%d) must be type of CTS_STRUCT_CONTACT.", contact->s_type);
+
+       switch (field)
+       {
+       case CTS_CF_NUMBER_LIST:
+               ret = cts_struct_store_num_list((contact_t *)contact, list);
+               retvm_if(CTS_SUCCESS != ret, ret, "cts_struct_store_num_list() Failed(%d)",ret);
+               break;
+       case CTS_CF_EMAIL_LIST:
+               ret = cts_struct_store_email_list((contact_t *)contact, list);
+               retvm_if(CTS_SUCCESS != ret, ret, "cts_struct_store_email_list() Failed(%d)",ret);
+               break;
+       case CTS_CF_GROUPREL_LIST:
+               ret = cts_struct_store_grouprel_list((contact_t *)contact, list);
+               retvm_if(CTS_SUCCESS != ret, ret, "cts_struct_store_grouprel_list() Failed(%d)",ret);
+               break;
+       case CTS_CF_EVENT_LIST:
+               ret = cts_struct_store_event_list((contact_t *)contact, list);
+               retvm_if(CTS_SUCCESS != ret, ret, "cts_struct_store_event_list() Failed(%d)",ret);
+               break;
+       case CTS_CF_MESSENGER_LIST:
+               ret = cts_struct_store_messenger_list((contact_t *)contact, list);
+               retvm_if(CTS_SUCCESS != ret, ret, "cts_struct_store_messenger_list() Failed(%d)",ret);
+               break;
+       case CTS_CF_POSTAL_ADDR_LIST:
+               ret = cts_struct_store_postal_list((contact_t *)contact, list);
+               retvm_if(CTS_SUCCESS != ret, ret, "cts_struct_store_postal_list() Failed(%d)",ret);
+               break;
+       case CTS_CF_WEB_ADDR_LIST:
+               ret = cts_struct_store_web_list((contact_t *)contact, list);
+               retvm_if(CTS_SUCCESS != ret, ret, "cts_struct_store_web_list() Failed(%d)",ret);
+               break;
+       case CTS_CF_NICKNAME_LIST:
+               ret = cts_struct_store_nickname_list((contact_t *)contact, list);
+               retvm_if(CTS_SUCCESS != ret, ret, "cts_struct_store_nickname_list() Failed(%d)",ret);
+               break;
+       default:
+               ERR("The parameter(field) is invalid"
+                               "You MUST be (CTS_CF_VALUE_MAX < field < CTS_CF_FIELD_MAX).");
+               return CTS_ERR_ARG_INVALID;
+       }
+       return CTS_SUCCESS;
+}
+
+static inline void cts_contact_store_name(contact_t *contact, cts_name *value)
+{
+       if (contact->name)
+       {
+               if (value->is_changed) {
+                       FREEandSTRDUP(contact->name->first, value->first);
+                       FREEandSTRDUP(contact->name->last, value->last);
+                       FREEandSTRDUP(contact->name->addition, value->addition);
+                       FREEandSTRDUP(contact->name->display, value->display);
+                       FREEandSTRDUP(contact->name->prefix, value->prefix);
+                       FREEandSTRDUP(contact->name->suffix, value->suffix);
+                       contact->name->is_changed = true;
+               }
+       }
+       else
+       {
+               //contact->name = (cts_name *)contacts_svc_value_new(CTS_VALUE_NAME);
+               contact->name = value;
+               contact->name->embedded = true;
+               contact->name->first = SAFE_STRDUP(value->first);
+               contact->name->last = SAFE_STRDUP(value->last);
+               contact->name->addition = SAFE_STRDUP(value->addition);
+               contact->name->display = SAFE_STRDUP(value->display);
+               contact->name->prefix = SAFE_STRDUP(value->prefix);
+               contact->name->suffix = SAFE_STRDUP(value->suffix);
+       }
+}
+
+static inline void cts_contact_store_base(contact_t *contact, cts_ct_base *value)
+{
+       if (contact->base)
+       {
+               if (value->uid_changed) {
+                       FREEandSTRDUP(contact->base->uid, value->uid);
+                       contact->base->uid_changed = true;
+               }
+               if (value->img_changed) {
+                       FREEandSTRDUP(contact->base->img_path, value->img_path);
+                       contact->base->img_changed = true;
+               }
+               if (value->full_img_changed) {
+                       FREEandSTRDUP(contact->base->full_img_path, value->full_img_path);
+                       contact->base->full_img_changed = true;
+               }
+               if (value->ringtone_changed) {
+                       FREEandSTRDUP(contact->base->ringtone_path, value->ringtone_path);
+                       contact->base->ringtone_changed = true;
+               }
+               if (value->note_changed) {
+                       FREEandSTRDUP(contact->base->note, value->note);
+                       contact->base->note_changed = true;
+               }
+       }
+       else
+       {
+               contact->base = value;
+               contact->base->embedded = true;
+               contact->base->uid = SAFE_STRDUP(value->uid);
+               contact->base->img_path = SAFE_STRDUP(value->img_path);
+               contact->base->full_img_path = SAFE_STRDUP(value->full_img_path);
+               contact->base->ringtone_path = SAFE_STRDUP(value->ringtone_path);
+               contact->base->note = SAFE_STRDUP(value->note);
+       }
+}
+
+static inline void cts_contact_store_company(contact_t *contact, cts_company *value)
+{
+       if (contact->company)
+       {
+               FREEandSTRDUP(contact->company->name, value->name);
+               FREEandSTRDUP(contact->company->department, value->department);
+               FREEandSTRDUP(contact->company->jot_title, value->jot_title);
+               FREEandSTRDUP(contact->company->role, value->role);
+               FREEandSTRDUP(contact->company->assistant_name, value->assistant_name);
+       }
+       else
+       {
+               //contact->company = (cts_company *)contacts_svc_value_new(CTS_VALUE_COMPANY);
+               contact->company = value;
+               contact->company->embedded = true;
+               contact->company->name = SAFE_STRDUP(value->name);
+               contact->company->department = SAFE_STRDUP(value->department);
+               contact->company->jot_title = SAFE_STRDUP(value->jot_title);
+               contact->company->role = SAFE_STRDUP(value->role);
+               contact->company->assistant_name = SAFE_STRDUP(value->assistant_name);
+       }
+}
+
+static inline int cts_contact_store_extend(contact_t *contact,
+               int type, cts_extend *value)
+{
+       cts_extend *stored_extend;
+
+       stored_extend = cts_extend_slist_search(type, contact->extended_values);
+       if (NULL == stored_extend)
+       {
+               retvm_if(value->embedded, CTS_ERR_ARG_INVALID, "This Value is already stored");
+               value->embedded = true;
+               value->type = type;
+               contact->extended_values = g_slist_append(contact->extended_values, value);
+               value->data2 = SAFE_STRDUP(value->data2);
+               value->data3 = SAFE_STRDUP(value->data3);
+               value->data4 = SAFE_STRDUP(value->data4);
+               value->data5 = SAFE_STRDUP(value->data5);
+               value->data6 = SAFE_STRDUP(value->data6);
+               value->data7 = SAFE_STRDUP(value->data7);
+               value->data8 = SAFE_STRDUP(value->data8);
+               value->data9 = SAFE_STRDUP(value->data9);
+               value->data10 = SAFE_STRDUP(value->data10);
+       }
+       else
+       {
+               retvm_if(stored_extend == value, CTS_SUCCESS, "This value is already stored");
+
+               FREEandSTRDUP(stored_extend->data2, value->data2);
+               FREEandSTRDUP(stored_extend->data3, value->data3);
+               FREEandSTRDUP(stored_extend->data4, value->data4);
+               FREEandSTRDUP(stored_extend->data5, value->data5);
+               FREEandSTRDUP(stored_extend->data6, value->data6);
+               FREEandSTRDUP(stored_extend->data7, value->data7);
+               FREEandSTRDUP(stored_extend->data8, value->data8);
+               FREEandSTRDUP(stored_extend->data9, value->data9);
+               FREEandSTRDUP(stored_extend->data10, value->data10);
+       }
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_struct_store_value(CTSstruct *contact,
+               cts_struct_field field, CTSvalue *value)
+{
+       contact_t *record = (contact_t *)contact;
+
+       retv_if(NULL == contact, CTS_ERR_ARG_NULL);
+       retv_if(NULL == value, CTS_ERR_ARG_NULL);
+       retvm_if(CTS_STRUCT_CONTACT != contact->s_type, CTS_ERR_ARG_INVALID,
+                       "The contact(%d) must be type of CTS_STRUCT_CONTACT.", contact->s_type);
+       CTS_DBG("contact type = %d, field = %d, value type = %d",
+                       contact->s_type, field, value->v_type);
+
+       switch (field)
+       {
+       case CTS_CF_NAME_VALUE:
+               retvm_if(CTS_VALUE_NAME != value->v_type, CTS_ERR_ARG_INVALID,
+                               "The value must be a CTS_VALUE_NAME for field(CTS_CF_NAME_VALUE).");
+               if (record->name != (cts_name *)value)
+                       cts_contact_store_name(record, (cts_name *)value);
+               break;
+       case CTS_CF_BASE_INFO_VALUE:
+               retvm_if(CTS_VALUE_CONTACT_BASE_INFO != value->v_type, CTS_ERR_ARG_INVALID,
+                               "The value must be a CTS_VALUE_CONTACT_BASE_INFO for field(CTS_CF_IMAGE_PATH_STR).");
+               if (record->base != (cts_ct_base *)value)
+                       cts_contact_store_base(record, (cts_ct_base*)value);
+               break;
+       case CTS_CF_COMPANY_VALUE:
+               retvm_if(CTS_VALUE_COMPANY != value->v_type, CTS_ERR_ARG_INVALID,
+                               "The value must be a CTS_VALUE_COMPANY for field(CTS_CF_COMPANY_VALUE).");
+               if (record->company != (cts_company *)value)
+                       cts_contact_store_company(record, (cts_company*)value);
+               break;
+       default:
+               if (CTS_VALUE_EXTEND == value->v_type && (int)CTS_DATA_EXTEND_START <= field)
+                       return cts_contact_store_extend(record, field, (cts_extend*)value);
+               ERR("The parameter(field:%d) is invalid"
+                               "You MUST be (CTS_CF_NONE < field < CTS_CF_VALUE_MAX).", field);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       return CTS_SUCCESS;
+}
+
+API CTSvalue* contacts_svc_value_new(cts_value_type type)
+{
+       CTSvalue* ret_val;
+       switch ((int)type)
+       {
+       case CTS_VALUE_BASIC:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_basic));
+               break;
+       case CTS_VALUE_CONTACT_BASE_INFO:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_ct_base));
+               break;
+       case CTS_VALUE_NAME:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_name));
+               break;
+       case CTS_VALUE_EMAIL:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_email));
+               break;
+       case CTS_VALUE_NUMBER:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_number));
+               break;
+       case CTS_VALUE_WEB:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_web));
+               break;
+       case CTS_VALUE_POSTAL:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_postal));
+               break;
+       case CTS_VALUE_EVENT:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_event));
+               break;
+       case CTS_VALUE_MESSENGER:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_messenger));
+               if (ret_val) ret_val->v_type = CTS_VALUE_MESSENGER;
+               break;
+       case CTS_VALUE_NICKNAME:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_nickname));
+               break;
+       case CTS_VALUE_GROUP_RELATION:
+       case CTS_VALUE_GROUP:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_group));
+               break;
+       case CTS_VALUE_COMPANY:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_company));
+               break;
+       case CTS_VALUE_PHONELOG:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_plog));
+               break;
+       case CTS_VALUE_EXTEND:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_extend));
+               break;
+       case CTS_VALUE_ADDRESSBOOK:
+               ret_val = (CTSvalue*)calloc(1, sizeof(cts_addrbook));
+               break;
+       case CTS_VALUE_LIST_CONTACT:
+               if (contact_list_mempool) {
+                       memset(contact_list_mempool, 0x00, sizeof(contact_list));
+                       ret_val = (CTSvalue*)contact_list_mempool;
+                       contact_list_mempool = NULL;
+               }
+               else
+                       ret_val = (CTSvalue*)calloc(1, sizeof(contact_list));
+               break;
+       case CTS_VALUE_LIST_PLOG:
+               if (plog_list_mempool) {
+                       memset(plog_list_mempool, 0x00, sizeof(plog_list));
+                       ret_val = (CTSvalue*)plog_list_mempool;
+                       plog_list_mempool = NULL;
+               }
+               else
+                       ret_val = (CTSvalue*)calloc(1, sizeof(plog_list));
+               break;
+       case CTS_VALUE_LIST_CUSTOM_NUM_TYPE:
+               if (numtype_list_mempool) {
+                       memset(numtype_list_mempool, 0x00, sizeof(numtype_list));
+                       ret_val = (CTSvalue*)numtype_list_mempool;
+                       numtype_list_mempool = NULL;
+               }
+               else
+                       ret_val = (CTSvalue*)calloc(1, sizeof(numtype_list));
+               break;
+       case CTS_VALUE_LIST_CHANGE:
+               if (change_list_mempool) {
+                       memset(change_list_mempool, 0x00, sizeof(change_list));
+                       ret_val = (CTSvalue*)change_list_mempool;
+                       change_list_mempool = NULL;
+               }
+               else
+                       ret_val = (CTSvalue*)calloc(1, sizeof(change_list));
+               break;
+       case CTS_VALUE_LIST_ADDRBOOK:
+               if (addrbook_list_mempool) {
+                       memset(addrbook_list_mempool, 0x00, sizeof(cts_addrbook));
+                       ret_val = (CTSvalue*)addrbook_list_mempool;
+                       addrbook_list_mempool = NULL;
+               }
+               else
+                       ret_val = (CTSvalue*)calloc(1, sizeof(cts_addrbook));
+               break;
+       case CTS_VALUE_LIST_GROUP:
+               if (group_list_mempool) {
+                       memset(group_list_mempool, 0x00, sizeof(cts_group));
+                       ret_val = (CTSvalue*)group_list_mempool;
+                       group_list_mempool = NULL;
+               }
+               else
+                       ret_val = (CTSvalue*)calloc(1, sizeof(cts_group));
+               break;
+       case CTS_VALUE_LIST_SHORTCUT:
+               if (favorite_list_mempool) {
+                       memset(favorite_list_mempool, 0x00, sizeof(shortcut_list));
+                       ret_val = (CTSvalue*)favorite_list_mempool;
+                       favorite_list_mempool = NULL;
+               }
+               else
+                       ret_val = (CTSvalue*)calloc(1, sizeof(shortcut_list));
+               break;
+       case CTS_VALUE_LIST_SDN:
+               if (sdn_list_mempool) {
+                       memset(sdn_list_mempool, 0x00, sizeof(sdn_list));
+                       ret_val = (CTSvalue*)sdn_list_mempool;
+                       sdn_list_mempool = NULL;
+               }
+               else
+                       ret_val = (CTSvalue*)calloc(1, sizeof(sdn_list));
+               break;
+       default:
+               ERR("your type is Not supported");
+               return NULL;
+       }
+
+       if (ret_val)
+               ret_val->v_type = type;
+       else
+               ERR("calloc() Failed(%d)", errno);
+
+       return ret_val;
+}
+
+static inline void cts_internal_value_info_free(CTSvalue *value)
+{
+       plog_list *plog;
+       cts_plog *log;
+       numtype_list *numtype;
+       contact_list *contact;
+       change_list *change;
+       shortcut_list *favorite;
+       cts_group *group;
+       cts_addrbook *ab;
+       sdn_list *sdn;
+
+       switch (value->v_type)
+       {
+       case CTS_VALUE_LIST_CONTACT:
+       case CTS_VALUE_LIST_NUMBERINFO:
+       case CTS_VALUE_LIST_EMAILINFO:
+               contact = (contact_list *)value;
+               free(contact->img_path);
+               free(contact->first);
+               free(contact->last);
+               free(contact->display);
+               free(contact->connect);
+               free(contact->normalize);
+
+               if (!contact_list_mempool) {
+                       contact_list_mempool = contact;
+               }
+               else
+                       if (contact_list_mempool != contact)
+                               free(contact);
+               break;
+       case CTS_VALUE_LIST_PLOG:
+               plog = (plog_list *)value;
+               free(plog->first);
+               free(plog->last);
+               free(plog->display);
+               free(plog->img_path);
+
+               if (!plog_list_mempool) {
+                       plog_list_mempool = plog;
+               }
+               else
+                       if (plog_list_mempool != plog)
+                               free(plog);
+               break;
+       case CTS_VALUE_LIST_CUSTOM_NUM_TYPE:
+               numtype = (numtype_list *)value;
+               free(numtype->name);
+               if (!numtype_list_mempool) {
+                       numtype_list_mempool = numtype;
+               }
+               else
+                       if (numtype_list_mempool != numtype)
+                               free(numtype);
+               break;
+       case CTS_VALUE_LIST_CHANGE:
+               change = (change_list *)value;
+               if (!change_list_mempool) {
+                       change_list_mempool = change;
+               }
+               else
+                       if (change_list_mempool != change)
+                               free(change);
+               break;
+       case CTS_VALUE_LIST_GROUP:
+               group = (cts_group *)value;
+               free(group->name);
+
+               if (!group_list_mempool) {
+                       group_list_mempool = group;
+               }
+               else
+                       if (group_list_mempool != group)
+                               free(group);
+               break;
+       case CTS_VALUE_LIST_ADDRBOOK:
+               ab = (cts_addrbook *)value;
+               free(ab->name);
+
+               if (!addrbook_list_mempool) {
+                       addrbook_list_mempool = ab;
+               }
+               else
+                       if (addrbook_list_mempool != ab)
+                               free(ab);
+               break;
+       case CTS_VALUE_LIST_SHORTCUT:
+               favorite = (shortcut_list *)value;
+               free(favorite->first);
+               free(favorite->last);
+               free(favorite->display);
+               free(favorite->number);
+               free(favorite->img_path);
+
+               if (!favorite_list_mempool) {
+                       favorite_list_mempool = favorite;
+               }
+               else
+                       if (favorite_list_mempool != favorite)
+                               free(favorite);
+               break;
+       case CTS_VALUE_LIST_SDN:
+               sdn = (sdn_list *)value;
+               free(sdn->name);
+               free(sdn->number);
+
+               if (!sdn_list_mempool) {
+                       sdn_list_mempool = sdn;
+               }
+               else
+                       if (sdn_list_mempool != sdn)
+                               free(sdn);
+               break;
+       case CTS_VALUE_RDONLY_NAME:
+               cts_name_free((cts_name *)value);
+               break;
+       case CTS_VALUE_RDONLY_NUMBER:
+               cts_number_free(value, NULL);
+               break;
+       case CTS_VALUE_RDONLY_EMAIL:
+               cts_email_free(value, NULL);
+               break;
+       case CTS_VALUE_RDONLY_COMPANY:
+               cts_company_free((cts_company *)value);
+               break;
+       case CTS_VALUE_RDONLY_PLOG:
+               log = (cts_plog *)value;
+               free(log->number);
+               free(log->extra_data2);
+               free(log);
+               break;
+       default:
+               ERR("The type of value is unknown type(%d)", value->v_type);
+               return;
+       }
+}
+
+API int contacts_svc_value_free(CTSvalue *value)
+{
+       retv_if(NULL == value, CTS_ERR_ARG_NULL);
+
+       if (CTS_VALUE_LIST_CONTACT <= value->v_type)
+               cts_internal_value_info_free(value);
+       else {
+               switch (value->v_type) {
+               case CTS_VALUE_GROUP:
+                       if (value->embedded) {
+                               free(((cts_group *)value)->name);
+                               free(((cts_group *)value)->ringtone_path);
+                       }
+                       break;
+               case CTS_VALUE_ADDRESSBOOK:
+                       if (value->embedded) {
+                               free(((cts_addrbook *)value)->name);
+                       }
+                       break;
+               default:
+                       if (value->embedded) {
+                               DBG("This is the value of struct. It is really freed with the struct.");
+                               return CTS_SUCCESS;
+                       }
+                       break;
+               }
+               free(value);
+       }
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_value_get_type(CTSvalue *value)
+{
+       retv_if(NULL == value, CTS_ERR_ARG_NULL);
+
+       return value->v_type;
+}
+
+static inline int cts_value_get_int_base(cts_ct_base *value, int field)
+{
+       int ret = 0;
+
+       switch (field)
+       {
+       case CTS_BASE_VAL_ID_INT:
+               ret = value->id;
+               break;
+       case CTS_BASE_VAL_CHANGED_TIME_INT:
+               ret = value->changed_time;
+               break;
+       case CTS_BASE_VAL_ADDRESSBOOK_ID_INT:
+               ret = value->addrbook_id;
+               break;
+       default:
+               ERR("The field(%d) is not supported in value(Base_info)", field);
+               break;
+       }
+       return ret;
+}
+
+static inline int cts_value_get_int_plog_list(plog_list *value, int field)
+{
+       int ret = 0;
+
+       switch (field)
+       {
+       case CTS_LIST_PLOG_ID_INT:
+               ret = value->id;
+               break;
+       case CTS_LIST_PLOG_RELATED_ID_INT:
+               ret = value->related_id;
+               break;
+       case CTS_LIST_PLOG_NUM_TYPE_INT:
+               ret = value->num_type;
+               break;
+       case CTS_LIST_PLOG_LOG_TIME_INT:
+               ret = value->log_time;
+               break;
+       case CTS_LIST_PLOG_LOG_TYPE_INT:
+               ret = value->log_type;
+               break;
+       case CTS_LIST_PLOG_DURATION_INT:
+       case CTS_LIST_PLOG_MSGID_INT:
+               ret = value->extra_data1;
+               break;
+       default:
+               ERR("The field(%d) is not supported in value(plog list)", field);
+               break;
+       }
+       return ret;
+}
+
+static inline int cts_value_get_int_plog(cts_plog *value, int field)
+{
+       int ret = 0;
+
+       switch (field)
+       {
+       case CTS_PLOG_VAL_ID_INT:
+               ret = value->id;
+               break;
+       case CTS_PLOG_VAL_RELATED_ID_INT:
+               ret = value->related_id;
+               break;
+       case CTS_PLOG_VAL_LOG_TIME_INT:
+               ret = value->log_time;
+               break;
+       case CTS_PLOG_VAL_LOG_TYPE_INT:
+               ret = value->log_type;
+               break;
+       case CTS_PLOG_VAL_DURATION_INT:
+       case CTS_PLOG_VAL_MSGID_INT:
+               ret = value->extra_data1;
+               break;
+       default:
+               ERR("The field(%d) is not supported in value(plog)", field);
+               break;
+       }
+       return ret;
+}
+
+static inline int cts_value_get_int_change_list(change_list *value, int field)
+{
+       int ret = 0;
+
+       switch (field)
+       {
+       case CTS_LIST_CHANGE_ID_INT:
+               ret = value->id;
+               break;
+       case CTS_LIST_CHANGE_TYPE_INT:
+               ret = value->changed_type;
+               break;
+       case CTS_LIST_CHANGE_VER_INT:
+               ret = value->changed_ver;
+               break;
+       default:
+               ERR("The field(%d) is not supported in value(change list)", field);
+               break;
+       }
+       return ret;
+}
+
+static inline int cts_value_get_int_shortcut_list(shortcut_list *value, int field)
+{
+       int ret = 0;
+
+       switch (field)
+       {
+       case CTS_LIST_SHORTCUT_ID_INT:
+               ret = value->id;
+               break;
+       case CTS_LIST_SHORTCUT_CONTACT_ID_INT:
+               ret = value->contact_id;
+               break;
+       case CTS_LIST_SHORTCUT_NUMBER_TYPE_INT:
+               ret = value->num_type;
+               break;
+       case CTS_LIST_SHORTCUT_SPEEDDIAL_INT:
+               ret = value->speeddial;
+               break;
+       default:
+               ERR("The field(%d) is not supported in value(shorcut list)", field);
+               break;
+       }
+       return ret;
+}
+
+static inline int cts_value_get_int_addrbook(cts_addrbook *value, int field)
+{
+       int ret = 0;
+
+       switch (field)
+       {
+       case CTS_ADDRESSBOOK_VAL_ID_INT:
+               ret = value->id;
+               break;
+       case CTS_ADDRESSBOOK_VAL_ACC_ID_INT:
+               ret = value->acc_id;
+               break;
+       case CTS_ADDRESSBOOK_VAL_ACC_TYPE_INT:
+               ret = value->acc_type;
+               break;
+       case CTS_ADDRESSBOOK_VAL_MODE_INT:
+               ret = value->mode;
+               break;
+       default:
+               ERR("The field(%d) is not supported in value(addressbook)", field);
+               break;
+       }
+       return ret;
+}
+
+API int contacts_svc_value_get_int(CTSvalue *value, int field)
+{
+       int ret = 0;
+       retvm_if(NULL == value, 0, "The Parameter(value) is NULL");
+
+       switch (value->v_type)
+       {
+       case CTS_VALUE_BASIC:
+               retvm_if(CTS_BASIC_VAL_INT != ((cts_basic*)value)->type, 0,
+                               "The type of Basic_value is not integer");
+               ret = ((cts_basic*)value)->val.i;
+               break;
+       case CTS_VALUE_CONTACT_BASE_INFO:
+               ret = cts_value_get_int_base((cts_ct_base *)value, field);
+               break;
+       case CTS_VALUE_EXTEND:
+               if (CTS_EXTEND_VAL_DATA1_INT == field)
+                       ret = ((cts_extend*)value)->data1;
+               else
+                       ERR("The field(%d) is not supported in value(Extend)", field);
+               break;
+       case CTS_VALUE_RDONLY_NUMBER:
+       case CTS_VALUE_NUMBER:
+               if (CTS_NUM_VAL_ID_INT == field)
+                       ret = ((cts_number*)value)->id;
+               else if (CTS_NUM_VAL_TYPE_INT == field)
+                       ret = ((cts_number*)value)->type;
+               else
+                       ERR("The field(%d) is not supported in value(Number)", field);
+               break;
+       case CTS_VALUE_RDONLY_EMAIL:
+       case CTS_VALUE_EMAIL:
+               retvm_if(CTS_EMAIL_VAL_TYPE_INT != field, 0,
+                               "The field(%d) is not supported in value(Email)", field);
+               ret = ((cts_email*)value)->type;
+               break;
+       case CTS_VALUE_LIST_PLOG:
+               ret = cts_value_get_int_plog_list((plog_list *)value, field);
+               break;
+       case CTS_VALUE_RDONLY_PLOG:
+               ret = cts_value_get_int_plog((cts_plog *)value, field);
+               break;
+       case CTS_VALUE_LIST_CONTACT:
+       case CTS_VALUE_LIST_NUMS_EMAILS:
+               if (CTS_LIST_CONTACT_ID_INT == field)
+                       ret = ((contact_list *)value)->id;
+               else if (CTS_LIST_CONTACT_ADDRESSBOOK_ID_INT == field)
+                       ret = ((contact_list *)value)->acc_id;
+               else
+                       ERR("The field(%d) is not supported in value(contact_list)", field);
+               break;
+       case CTS_VALUE_ADDRESSBOOK:
+       case CTS_VALUE_LIST_ADDRBOOK:
+               ret = cts_value_get_int_addrbook((cts_addrbook *)value, field);
+               break;
+       case CTS_VALUE_LIST_NUMBERINFO:
+       case CTS_VALUE_LIST_EMAILINFO: // CTS_LIST_EMAIL_CONTACT_ID_INT is same to CTS_LIST_NUM_CONTACT_ID_INT
+               retvm_if(CTS_LIST_NUM_CONTACT_ID_INT != field, 0,
+                               "The field(%d) is not supported in value(Number list)", field);
+               ret = ((contact_list*)value)->id;
+               break;
+       case CTS_VALUE_LIST_GROUP:
+               if (CTS_LIST_GROUP_ID_INT == field)
+                       ret = ((cts_group *)value)->id;
+               else if (CTS_LIST_GROUP_ADDRESSBOOK_ID_INT == field)
+                       ret = ((cts_group *)value)->addrbook_id;
+               else
+                       ERR("Not supported field(%d)", field);
+               break;
+       case CTS_VALUE_LIST_CHANGE:
+               ret = cts_value_get_int_change_list((change_list *)value, field);
+               break;
+       case CTS_VALUE_LIST_SHORTCUT:
+               ret = cts_value_get_int_shortcut_list((shortcut_list *)value, field);
+               break;
+       case CTS_VALUE_MESSENGER:
+               if (CTS_MESSENGER_VAL_TYPE_INT == field)
+                       ret = ((cts_messenger*)value)->type;
+               else
+                       ERR("Not supported field(%d)", field);
+               break;
+       case CTS_VALUE_GROUP_RELATION:
+               if (CTS_GROUPREL_VAL_ID_INT == field)
+                       ret = ((cts_group*)value)->id;
+               else
+                       ERR("Not supported field(%d)", field);
+               break;
+       case CTS_VALUE_GROUP:
+               if (CTS_GROUP_VAL_ID_INT == field)
+                       ret = ((cts_group*)value)->id;
+               if (CTS_GROUP_VAL_ADDRESSBOOK_ID_INT == field)
+                       ret = ((cts_group*)value)->addrbook_id;
+               else
+                       ERR("Not supported field(%d)", field);
+               break;
+       case CTS_VALUE_WEB:
+               if (CTS_WEB_VAL_TYPE_INT == field)
+                       ret = ((cts_web*)value)->type;
+               else
+                       ERR("Not supported field(%d)", field);
+               break;
+       case CTS_VALUE_POSTAL:
+               if (CTS_POSTAL_VAL_TYPE_INT == field)
+                       ret = ((cts_postal*)value)->type;
+               else
+                       ERR("Not supported field(%d)", field);
+               break;
+       case CTS_VALUE_EVENT:
+               if (CTS_EVENT_VAL_TYPE_INT == field)
+                       ret = ((cts_event *)value)->type;
+               else if (CTS_EVENT_VAL_DATE_INT == field)
+                       ret = ((cts_event *)value)->date;
+               else
+                       ERR("Not supported field(%d)", field);
+               break;
+       case CTS_VALUE_PHONELOG:
+               /* phonelog value is write only */
+       case CTS_VALUE_COMPANY:
+               /* company value doesn't have interger value */
+       case CTS_VALUE_NAME:
+               /* name value doesn't have interger value */
+       default:
+               ERR("The value has unsupported type");
+               break;
+       }
+       return ret;
+}
+
+double contacts_svc_value_get_dbl(CTSvalue *value, int field)
+{
+       retv_if(NULL == value, CTS_ERR_ARG_NULL);
+
+       switch (value->v_type)
+       {
+       case CTS_VALUE_BASIC:
+               retvm_if(CTS_BASIC_VAL_DBL != ((cts_basic*)value)->type, 0.0,
+                               "The type of value is not double");
+               return ((cts_basic*)value)->val.d;
+       case CTS_VALUE_NAME:
+       case CTS_VALUE_EMAIL:
+       case CTS_VALUE_NUMBER:
+       case CTS_VALUE_WEB:
+       case CTS_VALUE_POSTAL:
+       case CTS_VALUE_EVENT:
+       case CTS_VALUE_MESSENGER:
+       case CTS_VALUE_GROUP_RELATION:
+       case CTS_VALUE_COMPANY:
+       default:
+               ERR("The value has unsupported type");
+               return CTS_ERR_ARG_INVALID;
+       }
+
+}
+
+API bool contacts_svc_value_get_bool(CTSvalue *value, int field)
+{
+       retvm_if(NULL == value, false, "The Parameter(value) is NULL");
+
+       switch (value->v_type)
+       {
+       case CTS_VALUE_CONTACT_BASE_INFO:
+               if (CTS_BASE_VAL_FAVORITE_BOOL == field) {
+                       return ((cts_ct_base*)value)->is_favorite;
+               }
+               else {
+                       ERR("The field(%d) is not supported in value(BASE_INFO)", field);
+                       return false;
+               }
+       case CTS_VALUE_RDONLY_NUMBER:
+       case CTS_VALUE_NUMBER:
+               if (CTS_NUM_VAL_DEFAULT_BOOL == field) {
+                       return ((cts_number*)value)->is_default;
+               }
+               else if (CTS_NUM_VAL_DELETE_BOOL == field) {
+                       return value->deleted;
+               }
+               else if (CTS_NUM_VAL_FAVORITE_BOOL == field) {
+                       return ((cts_number*)value)->is_favorite;
+               }
+               else {
+                       ERR("The field(%d) is not supported in value(Number)", field);
+                       return false;
+               }
+       case CTS_VALUE_RDONLY_EMAIL:
+       case CTS_VALUE_EMAIL:
+               if (CTS_EMAIL_VAL_DEFAULT_BOOL == field) {
+                       return ((cts_email*)value)->is_default;
+               }
+               else if (CTS_EMAIL_VAL_DELETE_BOOL == field) {
+                       return value->deleted;
+               }
+               else {
+                       ERR("The field(%d) is not supported in value(Email)", field);
+                       return false;
+               }
+       case CTS_VALUE_GROUP_RELATION:
+               if (CTS_GROUPREL_VAL_DELETE_BOOL == field) {
+                       return value->deleted;
+               }
+               else {
+                       ERR("The field(%d) is not supported in value(Group)", field);
+                       return false;
+               }
+       case CTS_VALUE_EVENT:
+               if (CTS_EVENT_VAL_DELETE_BOOL == field) {
+                       return value->deleted;
+               }
+               else {
+                       ERR("The field(%d) is not supported in value(Event)", field);
+                       return false;
+               }
+       case CTS_VALUE_MESSENGER:
+               if (CTS_MESSENGER_VAL_DELETE_BOOL == field) {
+                       return value->deleted;
+               }
+               else {
+                       ERR("The field(%d) is not supported in value(Messenger)", field);
+                       return false;
+               }
+       case CTS_VALUE_POSTAL:
+               if (CTS_POSTAL_VAL_DELETE_BOOL == field) {
+                       return value->deleted;
+               }
+               else if (CTS_POSTAL_VAL_DEFAULT_BOOL == field) {
+                       return ((cts_postal*)value)->is_default;;
+               }
+               else {
+                       ERR("The field(%d) is not supported in value(Postal)", field);
+                       return false;
+               }
+       case CTS_VALUE_WEB:
+               if (CTS_WEB_VAL_DELETE_BOOL == field) {
+                       return value->deleted;
+               }
+               else {
+                       ERR("The field(%d) is not supported in value(Web)", field);
+                       return false;
+               }
+       case CTS_VALUE_NICKNAME:
+               if (CTS_NICKNAME_VAL_DELETE_BOOL == field) {
+                       return value->deleted;
+               }
+               else {
+                       ERR("The field(%d) is not supported in value(Web)", field);
+                       return false;
+               }
+       case CTS_VALUE_EXTEND:
+               if (CTS_EXTEND_VAL_DELETE_BOOL == field) {
+                       return value->deleted;
+               }
+               else {
+                       ERR("The field(%d) is not supported in value(Extend)", field);
+                       return false;
+               }
+       case CTS_VALUE_BASIC:
+               retvm_if(CTS_BASIC_VAL_BOOL != ((cts_basic*)value)->type, false,
+                               "The type of value is not boolean");
+               return ((cts_basic*)value)->val.b;
+       case CTS_VALUE_PHONELOG:
+               /* phonelog value is write only */
+       case CTS_VALUE_LIST_CONTACT:
+               /* contact list value doesn't have boolean value */
+       case CTS_VALUE_LIST_PLOG:
+               /* plog list value doesn't have boolean value */
+       case CTS_VALUE_LIST_CUSTOM_NUM_TYPE:
+               /* custom number type list value doesn't have boolean value */
+       case CTS_VALUE_LIST_CHANGE:
+               /* Change list value doesn't have boolean value */
+       case CTS_VALUE_NAME:
+               /* name value doesn't have boolean value */
+       case CTS_VALUE_COMPANY:
+               /* company value doesn't have boolean value */
+       default:
+               ERR("The value has unsupported type");
+               return false;
+       }
+}
+
+static inline char* cts_value_get_str_name(int op_code,
+               cts_name *value, int field)
+{
+       char *ret_val;
+
+       switch (field)
+       {
+       case CTS_NAME_VAL_FIRST_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->first);
+               break;
+       case CTS_NAME_VAL_LAST_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->last);
+               break;
+       case CTS_NAME_VAL_DISPLAY_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->display);
+               break;
+       case CTS_NAME_VAL_ADDITION_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->addition);
+               break;
+       case CTS_NAME_VAL_PREFIX_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->prefix);
+               break;
+       case CTS_NAME_VAL_SUFFIX_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->suffix);
+               break;
+       default:
+               ERR("The parameter(field:%d) is not interpreted", field);
+               ret_val = NULL;
+               break;
+       }
+       return ret_val;
+}
+
+static inline char* cts_value_get_str_extend(int op_code,
+               cts_extend *value, int field)
+{
+       char *ret_val;
+
+       switch (field)
+       {
+       case CTS_EXTEND_VAL_DATA2_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->data2);
+               break;
+       case CTS_EXTEND_VAL_DATA3_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->data3);
+               break;
+       case CTS_EXTEND_VAL_DATA4_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->data4);
+               break;
+       case CTS_EXTEND_VAL_DATA5_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->data5);
+               break;
+       case CTS_EXTEND_VAL_DATA6_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->data6);
+               break;
+       case CTS_EXTEND_VAL_DATA7_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->data7);
+               break;
+       case CTS_EXTEND_VAL_DATA8_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->data8);
+               break;
+       case CTS_EXTEND_VAL_DATA9_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->data9);
+               break;
+       case CTS_EXTEND_VAL_DATA10_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->data10);
+               break;
+       default:
+               ERR("The parameter(field:%d) is not interpreted", field);
+               ret_val = NULL;
+               break;
+       }
+       return ret_val;
+}
+
+static inline char* cts_value_get_str_base(int op_code,
+               cts_ct_base *value, int field)
+{
+       char *ret_val;
+
+       switch (field)
+       {
+       case CTS_BASE_VAL_IMG_PATH_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->img_path);
+               if (NULL == ret_val && value->vcard_img_path) {
+                       if (CTS_HANDLE_STR_STEAL == op_code)
+                               ret_val = strdup(value->vcard_img_path);
+                       else
+                               ret_val = value->vcard_img_path;
+               }
+               break;
+       case CTS_BASE_VAL_RINGTONE_PATH_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->ringtone_path);
+               break;
+       case CTS_BASE_VAL_NOTE_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->note);
+               break;
+       case CTS_BASE_VAL_UID_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->uid);
+               break;
+       case CTS_BASE_VAL_FULL_IMG_PATH_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->full_img_path);
+               break;
+       default:
+               ERR("The parameter(field:%d) is not interpreted", field);
+               ret_val = NULL;
+               break;
+       }
+       return ret_val;
+}
+
+static inline char* cts_value_get_str_contact_list(int op_code,
+               contact_list *value, int field)
+{
+       char *ret_val;
+       switch (field)
+       {
+       case CTS_LIST_CONTACT_FIRST_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->first);
+               break;
+       case CTS_LIST_CONTACT_LAST_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->last);
+               break;
+       case CTS_LIST_CONTACT_DISPLAY_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->display);
+               break;
+       case CTS_LIST_CONTACT_IMG_PATH_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->img_path);
+               break;
+       case CTS_LIST_CONTACT_NUM_OR_EMAIL_STR:
+               if (CTS_VALUE_LIST_NUMS_EMAILS == value->v_type) {
+                       HANDLE_STEAL_STRING(op_code, ret_val, value->connect);
+               } else {
+                       ERR("The parameter(field:%d, value type = %d) is not interpreted",
+                               field, value->v_type);
+                       ret_val = NULL;
+               }
+               break;
+       case CTS_LIST_CONTACT_NORMALIZED_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->normalize);
+               break;
+       default:
+               ERR("The parameter(field:%d) is not interpreted", field);
+               ret_val = NULL;
+               break;
+       }
+       return ret_val;
+}
+
+static inline char* cts_value_get_str_num_email_list(int op_code,
+               contact_list *value, int field, int type)
+{
+       char *ret_val;
+       switch (field)
+       {
+       case CTS_LIST_NUM_CONTACT_FIRST_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->first);
+               break;
+       case CTS_LIST_NUM_CONTACT_LAST_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->last);
+               break;
+       case CTS_LIST_NUM_CONTACT_DISPLAY_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->display);
+               break;
+       case CTS_LIST_NUM_CONTACT_IMG_PATH_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->img_path);
+               break;
+       case CTS_LIST_NUM_NUMBER_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->connect);
+               break;
+       default:
+               ERR("The parameter(field:%d) is not interpreted", field);
+               ret_val = NULL;
+               break;
+       }
+       return ret_val;
+}
+
+static inline char* cts_value_get_str_favorite_list(int op_code,
+               shortcut_list *value, int field)
+{
+       char *ret_val;
+       switch (field)
+       {
+       case CTS_LIST_SHORTCUT_FIRST_NAME_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->first);
+               break;
+       case CTS_LIST_SHORTCUT_LAST_NAME_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->last);
+               break;
+       case CTS_LIST_SHORTCUT_DISPLAY_NAME_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->display);
+               break;
+       case CTS_LIST_SHORTCUT_IMG_PATH_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->img_path);
+               break;
+       case CTS_LIST_SHORTCUT_NUMBER_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->number);
+               break;
+       default:
+               ERR("The parameter(field:%d) is not interpreted", field);
+               ret_val = NULL;
+               break;
+       }
+       return ret_val;
+}
+
+static inline char* cts_value_get_str_plog_list(int op_code,
+               plog_list *value, int field)
+{
+       char *ret_val;
+       switch (field)
+       {
+       case CTS_LIST_PLOG_FIRST_NAME_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->first);
+               break;
+       case CTS_LIST_PLOG_LAST_NAME_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->last);
+               break;
+       case CTS_LIST_PLOG_DISPLAY_NAME_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->display);
+               break;
+       case CTS_LIST_PLOG_NUMBER_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->number);
+               break;
+       case CTS_LIST_PLOG_IMG_PATH_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->img_path);
+               break;
+       case CTS_LIST_PLOG_SHORTMSG_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->extra_data2);
+               break;
+       default:
+               ERR("The parameter(field:%d) is not interpreted", field);
+               ret_val = NULL;
+               break;
+       }
+       return ret_val;
+}
+
+static inline char* cts_value_get_str_postal(int op_code,
+               cts_postal *value, int field)
+{
+       char *ret_val;
+       switch (field)
+       {
+       case CTS_POSTAL_VAL_POBOX_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->pobox);
+               break;
+       case CTS_POSTAL_VAL_POSTALCODE_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->postalcode);
+               break;
+       case CTS_POSTAL_VAL_REGION_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->region);
+               break;
+       case CTS_POSTAL_VAL_LOCALITY_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->locality);
+               break;
+       case CTS_POSTAL_VAL_STREET_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->street);
+               break;
+       case CTS_POSTAL_VAL_EXTENDED_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->extended);
+               break;
+       case CTS_POSTAL_VAL_COUNTRY_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->country);
+               break;
+       default:
+               ERR("The parameter(field:%d) is not interpreted", field);
+               ret_val = NULL;
+               break;
+       }
+       return ret_val;
+}
+
+static inline char* cts_value_get_str_company(int op_code,
+               cts_company *value, int field)
+{
+       char *ret_val;
+       switch (field)
+       {
+       case CTS_COMPANY_VAL_NAME_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->name);
+               break;
+       case CTS_COMPANY_VAL_DEPARTMENT_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->department);
+               break;
+       case CTS_COMPANY_VAL_JOB_TITLE_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->jot_title);
+               break;
+       case CTS_COMPANY_VAL_ROLE_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->role);
+               break;
+       case CTS_COMPANY_VAL_ASSISTANT_NAME_STR:
+               HANDLE_STEAL_STRING(op_code, ret_val, value->assistant_name);
+               break;
+       default:
+               ERR("The parameter(field:%d) is not interpreted", field);
+               ret_val = NULL;
+               break;
+       }
+       return ret_val;
+}
+
+static char* cts_value_handle_str(int op_code, CTSvalue *value, int field)
+{
+       char *ret_val;
+       retvm_if(NULL == value, NULL, "The Parameter(value) is NULL");
+
+       switch (value->v_type)
+       {
+       case CTS_VALUE_BASIC:
+               retvm_if(CTS_BASIC_VAL_STR != ((cts_basic *)value)->type, NULL,
+                               "The type of value is not string");
+               HANDLE_STEAL_STRING(op_code, ret_val, ((cts_basic *)value)->val.s);
+               break;
+       case CTS_VALUE_CONTACT_BASE_INFO:
+               ret_val = cts_value_get_str_base(op_code, (cts_ct_base *)value, field);
+               break;
+       case CTS_VALUE_POSTAL:
+               ret_val = cts_value_get_str_postal(op_code, (cts_postal *)value, field);
+               break;
+       case CTS_VALUE_COMPANY:
+       case CTS_VALUE_RDONLY_COMPANY:
+               ret_val = cts_value_get_str_company(op_code, (cts_company *)value, field);
+               break;
+       case CTS_VALUE_NAME:
+       case CTS_VALUE_RDONLY_NAME:
+               ret_val = cts_value_get_str_name(op_code, (cts_name *)value, field);
+               break;
+       case CTS_VALUE_EXTEND:
+               ret_val = cts_value_get_str_extend(op_code, (cts_extend *)value, field);
+               break;
+       case CTS_VALUE_LIST_CONTACT:
+       case CTS_VALUE_LIST_NUMS_EMAILS:
+               ret_val = cts_value_get_str_contact_list(op_code, (contact_list *)value, field);
+               break;
+       case CTS_VALUE_LIST_NUMBERINFO:
+       case CTS_VALUE_LIST_EMAILINFO:
+               ret_val = cts_value_get_str_num_email_list(op_code, (contact_list *)value, field, value->v_type);
+               break;
+       case CTS_VALUE_LIST_SHORTCUT:
+               ret_val = cts_value_get_str_favorite_list(op_code, (shortcut_list *)value, field);
+               break;
+       case CTS_VALUE_LIST_PLOG:
+               ret_val = cts_value_get_str_plog_list(op_code, (plog_list *)value, field);
+               break;
+       case CTS_VALUE_RDONLY_PLOG:
+               if (CTS_PLOG_VAL_NUMBER_STR == field) {
+                       HANDLE_STEAL_STRING(op_code, ret_val, ((cts_plog *)value)->number);
+               } else if (CTS_PLOG_VAL_SHORTMSG_STR == field) {
+                       HANDLE_STEAL_STRING(op_code, ret_val, ((cts_plog *)value)->extra_data2);
+               } else {
+                       ERR("Not supported field");
+                       return NULL;
+               }
+               break;
+       case CTS_VALUE_NUMBER:
+       case CTS_VALUE_RDONLY_NUMBER:
+               retvm_if(CTS_NUM_VAL_NUMBER_STR != field, NULL,
+                               "This field(%d) is not supported in value(Number)", field);
+               HANDLE_STEAL_STRING(op_code, ret_val, ((cts_number *)value)->number);
+               break;
+       case CTS_VALUE_EMAIL:
+       case CTS_VALUE_RDONLY_EMAIL:
+               retvm_if(CTS_EMAIL_VAL_ADDR_STR != field, NULL,
+                               "This field(%d) is not supported in value(Email)", field);
+               HANDLE_STEAL_STRING(op_code, ret_val, ((cts_email *)value)->email_addr);
+               break;
+       case CTS_VALUE_ADDRESSBOOK:
+       case CTS_VALUE_LIST_ADDRBOOK:
+               retvm_if(CTS_ADDRESSBOOK_VAL_NAME_STR != field, NULL,
+                               "This field(%d) is not supported in value(addressbook)", field);
+               HANDLE_STEAL_STRING(op_code, ret_val, ((cts_addrbook *)value)->name);
+               break;
+       case CTS_VALUE_GROUP_RELATION:
+               if (CTS_GROUPREL_VAL_NAME_STR == field) {
+                       HANDLE_STEAL_STRING(op_code, ret_val, ((cts_group *)value)->name);
+               }
+               else if (CTS_GROUPREL_VAL_RINGTONE_STR == field) {
+                       HANDLE_STEAL_STRING(op_code, ret_val, ((cts_group *)value)->ringtone_path);
+               }
+               else {
+                       ERR("Not supported field(%d)", field);
+                       ret_val = NULL;
+               }
+               break;
+       case CTS_VALUE_MESSENGER:
+               if (CTS_MESSENGER_VAL_IM_ID_STR == field) {
+                       HANDLE_STEAL_STRING(op_code, ret_val, ((cts_messenger *)value)->im_id);
+               }
+               else {
+                       ERR("Not supported field(%d)", field);
+                       ret_val = NULL;
+               }
+               break;
+       case CTS_VALUE_WEB:
+               if (CTS_WEB_VAL_ADDR_STR == field) {
+                       HANDLE_STEAL_STRING(op_code, ret_val, ((cts_web *)value)->url);
+               }
+               else {
+                       ERR("Not supported field(%d)", field);
+                       ret_val = NULL;
+               }
+               break;
+       case CTS_VALUE_NICKNAME:
+               if (CTS_NICKNAME_VAL_NAME_STR == field) {
+                       HANDLE_STEAL_STRING(op_code, ret_val, ((cts_nickname *)value)->nick);
+               }
+               else {
+                       ERR("Not supported field(%d)", field);
+                       ret_val = NULL;
+               }
+               break;
+       case CTS_VALUE_GROUP:
+               if (CTS_GROUP_VAL_NAME_STR == field) {
+                       HANDLE_STEAL_STRING(op_code, ret_val, ((cts_group *)value)->name);
+               }
+               else if (CTS_GROUP_VAL_RINGTONE_STR == field) {
+                       HANDLE_STEAL_STRING(op_code, ret_val, ((cts_group *)value)->ringtone_path);
+               }
+               else {
+                       ERR("Not supported field(%d)", field);
+                       ret_val = NULL;
+               }
+               break;
+       case CTS_VALUE_LIST_GROUP:
+               if (CTS_LIST_GROUP_NAME_STR == field) {
+                       HANDLE_STEAL_STRING(op_code, ret_val, ((cts_group *)value)->name);
+               }
+               else {
+                       ERR("Not supported field(%d)", field);
+                       ret_val = NULL;
+               }
+               break;
+       case CTS_VALUE_LIST_SDN:
+               if (CTS_LIST_SDN_NAME_STR == field) {
+                       HANDLE_STEAL_STRING(op_code, ret_val, ((sdn_list *)value)->name);
+               }
+               else if (CTS_LIST_SDN_NUMBER_STR == field) {
+                       HANDLE_STEAL_STRING(op_code, ret_val, ((sdn_list *)value)->number);
+               }
+               else {
+                       ERR("Not supported field(%d)", field);
+                       ret_val = NULL;
+               }
+               break;
+       case CTS_VALUE_PHONELOG:
+               /* phonelog value is write only */
+       case CTS_VALUE_LIST_CHANGE:
+               /* Change list value doesn't have string value */
+       case CTS_VALUE_EVENT:
+               /* evet value doesn't have string value */
+       default:
+               ERR("The value has unsupported type");
+               ret_val = NULL;
+               break;
+       }
+       return ret_val;
+}
+
+API const char* contacts_svc_value_get_str(CTSvalue *value, int field)
+{
+       return cts_value_handle_str(CTS_HANDLE_STR_GET, value, field);
+}
+
+API char* contacts_svc_value_steal_str(CTSvalue *value, int field)
+{
+       return cts_value_handle_str(CTS_HANDLE_STR_STEAL, value, field);
+}
+
+static inline int cts_value_set_int_plog(cts_plog *value, int field, int intval)
+{
+       switch (field)
+       {
+       case CTS_PLOG_VAL_LOG_TIME_INT:
+               value->log_time = intval;
+               break;
+       case CTS_PLOG_VAL_LOG_TYPE_INT:
+               value->log_type = intval;
+               break;
+       case CTS_PLOG_VAL_DURATION_INT:
+       case CTS_PLOG_VAL_MSGID_INT:
+               value->extra_data1 = intval;
+               break;
+       case CTS_PLOG_VAL_RELATED_ID_INT:
+               value->related_id = intval;
+               break;
+       default:
+               ERR("The field(%d) is not supported in value(plog)", field);
+               return CTS_ERR_ARG_INVALID;
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_value_set_int_addrbook(cts_addrbook *value,
+               int field, int intval)
+{
+       switch (field)
+       {
+       case CTS_ADDRESSBOOK_VAL_ACC_ID_INT:
+               value->acc_id = intval;
+               break;
+       case CTS_ADDRESSBOOK_VAL_ACC_TYPE_INT:
+               value->acc_type = intval;
+               break;
+       case CTS_ADDRESSBOOK_VAL_MODE_INT:
+               value->mode = intval;
+               break;
+       default:
+               ERR("The field(%d) is not supported in value(addressbook)", field);
+               return CTS_ERR_ARG_INVALID;
+       }
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_value_set_int(CTSvalue *value, int field, int intval)
+{
+       retv_if(NULL == value, CTS_ERR_ARG_NULL);
+
+       switch (value->v_type)
+       {
+       case CTS_VALUE_BASIC:
+               ((cts_basic*)value)->type = CTS_BASIC_VAL_INT;
+               ((cts_basic*)value)->val.i = intval;
+               break;
+       case CTS_VALUE_EXTEND:
+               retvm_if(CTS_EXTEND_VAL_DATA1_INT != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               ((cts_extend *)value)->data1 = intval;
+               break;
+       case CTS_VALUE_EMAIL:
+       case CTS_VALUE_NUMBER:
+               retvm_if(CTS_NUM_VAL_TYPE_INT != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               ((cts_number *)value)->type = intval;
+               break;
+       case CTS_VALUE_PHONELOG:
+               return cts_value_set_int_plog((cts_plog *)value, field, intval);
+       case CTS_VALUE_GROUP_RELATION:
+               retvm_if(CTS_GROUPREL_VAL_ID_INT != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               retvm_if(value->embedded, CTS_ERR_ARG_INVALID,
+                               "The field is only used for creating");
+               ((cts_group *)value)->id = intval;
+               break;
+       case CTS_VALUE_GROUP:
+               retvm_if(CTS_GROUP_VAL_ADDRESSBOOK_ID_INT != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               retvm_if(!value->embedded, CTS_ERR_ARG_INVALID,
+                               "The field is only used for updating");
+               ((cts_group *)value)->addrbook_id = intval;
+               break;
+       case CTS_VALUE_MESSENGER:
+               retvm_if(CTS_MESSENGER_VAL_TYPE_INT != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               ((cts_messenger *)value)->type = intval;
+               break;
+       case CTS_VALUE_WEB:
+               retvm_if(CTS_WEB_VAL_TYPE_INT != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               ((cts_web *)value)->type = intval;
+               break;
+       case CTS_VALUE_EVENT:
+               if (CTS_EVENT_VAL_TYPE_INT == field)
+                       ((cts_event *)value)->type = intval;
+               else if (CTS_EVENT_VAL_DATE_INT == field)
+                       ((cts_event *)value)->date = intval;
+               else
+               {
+                       ERR("Not supported field");
+                       return CTS_ERR_ARG_INVALID;
+               }
+               break;
+       case CTS_VALUE_POSTAL:
+               retvm_if(CTS_POSTAL_VAL_TYPE_INT != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               ((cts_postal *)value)->type = intval;
+               break;
+       case CTS_VALUE_ADDRESSBOOK:
+               return cts_value_set_int_addrbook((cts_addrbook *)value, field, intval);
+       case CTS_VALUE_COMPANY:
+               /* company value doesn't have integer value */
+       case CTS_VALUE_NAME:
+               /* name value doesn't have integer value */
+       case CTS_VALUE_CONTACT_BASE_INFO:
+               /* base_info value doesn't have integer value for set */
+       default:
+               ERR("The value has unsupported type");
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       return CTS_SUCCESS;
+}
+
+int contacts_svc_value_set_dbl(CTSvalue *value, int field, double dblval)
+{
+       retv_if(NULL == value, CTS_ERR_ARG_NULL);
+
+       switch (value->v_type)
+       {
+       case CTS_VALUE_BASIC:
+               ((cts_basic*)value)->type = CTS_BASIC_VAL_DBL;
+               ((cts_basic*)value)->val.d = dblval;
+               break;
+       case CTS_VALUE_EMAIL:
+       case CTS_VALUE_NUMBER:
+       case CTS_VALUE_WEB:
+       case CTS_VALUE_POSTAL:
+       case CTS_VALUE_EVENT:
+       case CTS_VALUE_MESSENGER:
+       case CTS_VALUE_GROUP_RELATION:
+       case CTS_VALUE_COMPANY:
+       case CTS_VALUE_NAME:
+       case CTS_VALUE_CONTACT_BASE_INFO:
+       default:
+               ERR("The value has unsupported type");
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_value_set_bool(CTSvalue *value,
+               int field, bool boolval)
+{
+       retv_if(NULL == value, CTS_ERR_ARG_NULL);
+
+       switch (value->v_type)
+       {
+       case CTS_VALUE_CONTACT_BASE_INFO:
+               if (CTS_BASE_VAL_FAVORITE_BOOL == field)
+                       ((cts_ct_base*)value)->is_favorite = boolval;
+               else {
+                       ERR("The field(%d) is not supported in value(BASE_INFO)", field);
+                       return CTS_ERR_ARG_INVALID;
+               }
+               break;
+       case CTS_VALUE_NUMBER:
+               if (CTS_NUM_VAL_DEFAULT_BOOL == field)
+                       ((cts_number *)value)->is_default = boolval;
+               else if (CTS_NUM_VAL_FAVORITE_BOOL == field)
+                       ((cts_number *)value)->is_favorite = boolval;
+               else if (CTS_NUM_VAL_DELETE_BOOL == field) {
+                       retvm_if(false == value->embedded, CTS_ERR_ARG_INVALID,
+                                       "The field is only used for updating");
+                       value->deleted = boolval;
+               }
+               else {
+                       ERR("Not supported field");
+                       return CTS_ERR_ARG_INVALID;
+               }
+               break;
+       case CTS_VALUE_EMAIL:
+               if (CTS_EMAIL_VAL_DEFAULT_BOOL == field)
+                       ((cts_email *)value)->is_default = boolval;
+               else if (CTS_EMAIL_VAL_DELETE_BOOL == field) {
+                       retvm_if(false == value->embedded, CTS_ERR_ARG_INVALID,
+                                       "The field is only used for updating");
+                       value->deleted = boolval;
+               }
+               else {
+                       ERR("Not supported field");
+                       return CTS_ERR_ARG_INVALID;
+               }
+               break;
+       case CTS_VALUE_POSTAL:
+               if (CTS_POSTAL_VAL_DEFAULT_BOOL == field)
+                       ((cts_postal *)value)->is_default = boolval;
+               else if (CTS_POSTAL_VAL_DELETE_BOOL == field) {
+                       retvm_if(false == value->embedded, CTS_ERR_ARG_INVALID,
+                                       "The field is only used for updating");
+                       value->deleted = boolval;
+               }
+               else {
+                       ERR("Not supported field");
+                       return CTS_ERR_ARG_INVALID;
+               }
+               break;
+       case CTS_VALUE_GROUP_RELATION:
+               retvm_if(CTS_GROUPREL_VAL_DELETE_BOOL != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               retvm_if(false == value->embedded, CTS_ERR_ARG_INVALID,
+                               "The field is only used for updating");
+               value->deleted = boolval;
+               break;
+       case CTS_VALUE_EVENT:
+               retvm_if(CTS_EVENT_VAL_DELETE_BOOL != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               retvm_if(false == value->embedded, CTS_ERR_ARG_INVALID,
+                               "The field is only used for updating");
+               value->deleted = boolval;
+               break;
+       case CTS_VALUE_MESSENGER:
+               retvm_if(CTS_MESSENGER_VAL_DELETE_BOOL != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               retvm_if(false == value->embedded, CTS_ERR_ARG_INVALID,
+                               "The field is only used for updating");
+               value->deleted = boolval;
+               break;
+       case CTS_VALUE_WEB:
+               retvm_if(CTS_WEB_VAL_DELETE_BOOL != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               retvm_if(false == value->embedded, CTS_ERR_ARG_INVALID,
+                               "The field is only used for updating");
+               value->deleted = boolval;
+               break;
+       case CTS_VALUE_NICKNAME:
+               retvm_if(CTS_NICKNAME_VAL_DELETE_BOOL != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               retvm_if(false == value->embedded, CTS_ERR_ARG_INVALID,
+                               "The field is only used for updating");
+               value->deleted = boolval;
+               break;
+       case CTS_VALUE_EXTEND:
+               retvm_if(CTS_EXTEND_VAL_DELETE_BOOL != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               retvm_if(false == value->embedded, CTS_ERR_ARG_INVALID,
+                               "The field is only used for updating");
+               value->deleted = boolval;
+               break;
+       case CTS_VALUE_BASIC:
+               ((cts_basic*)value)->type = CTS_BASIC_VAL_BOOL;
+               ((cts_basic*)value)->val.b = boolval;
+               break;
+       case CTS_VALUE_COMPANY:
+               /* company value doesn't have boolean value */
+       case CTS_VALUE_NAME:
+               /* name value doesn't have boolean value */
+       default:
+               ERR("The value has unsupported type");
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       return CTS_SUCCESS;
+}
+
+static inline int cts_base_set_str(cts_ct_base *base, int field, char *strval)
+{
+       switch (field)
+       {
+       case CTS_BASE_VAL_IMG_PATH_STR:
+               if (base->embedded)
+                       FREEandSTRDUP(base->img_path, strval);
+               else
+                       base->img_path = strval;
+               base->img_changed = true;
+               break;
+       case CTS_BASE_VAL_RINGTONE_PATH_STR:
+               if (base->embedded)
+                       FREEandSTRDUP(base->ringtone_path, strval);
+               else
+                       base->ringtone_path = strval;
+               base->ringtone_changed = true;
+               break;
+       case CTS_BASE_VAL_NOTE_STR:
+               if (base->embedded)
+                       FREEandSTRDUP(base->note, strval);
+               else
+                       base->note = strval;
+               base->note_changed = true;
+               break;
+       case CTS_BASE_VAL_UID_STR:
+               if (base->embedded)
+                       FREEandSTRDUP(base->uid, strval);
+               else
+                       base->uid = strval;
+               base->uid_changed = true;
+               break;
+       case CTS_BASE_VAL_FULL_IMG_PATH_STR:
+               if (base->embedded)
+                       FREEandSTRDUP(base->full_img_path, strval);
+               else
+                       base->full_img_path = strval;
+               base->full_img_changed = true;
+               break;
+       default:
+               ERR("Not supported field");
+               return CTS_ERR_ARG_INVALID;
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_name_set_str(cts_name *name, int field, char *strval)
+{
+       switch (field)
+       {
+       case CTS_NAME_VAL_FIRST_STR:
+               if (name->embedded) {
+                       FREEandSTRDUP(name->first, strval);
+               }
+               else
+                       name->first = strval;
+               break;
+       case CTS_NAME_VAL_LAST_STR:
+               if (name->embedded) {
+                       FREEandSTRDUP(name->last, strval);
+               }
+               else
+                       name->last = strval;
+               break;
+       case CTS_NAME_VAL_ADDITION_STR:
+               if (name->embedded) {
+                       FREEandSTRDUP(name->addition, strval);
+               }
+               else
+                       name->addition = strval;
+               break;
+       case CTS_NAME_VAL_DISPLAY_STR:
+               if (name->embedded) {
+                       FREEandSTRDUP(name->display, strval);
+               }
+               else
+                       name->display = strval;
+               break;
+       case CTS_NAME_VAL_PREFIX_STR:
+               if (name->embedded) {
+                       FREEandSTRDUP(name->prefix, strval);
+               }
+               else
+                       name->prefix = strval;
+               break;
+       case CTS_NAME_VAL_SUFFIX_STR:
+               if (name->embedded) {
+                       FREEandSTRDUP(name->suffix, strval);
+               }
+               else
+                       name->suffix = strval;
+               break;
+       default:
+               ERR("Not supported field");
+               return CTS_ERR_ARG_INVALID;
+       }
+       name->is_changed = true;
+       return CTS_SUCCESS;
+}
+
+static inline int cts_postal_set_str(cts_postal *postal, int field, char *strval)
+{
+       switch (field)
+       {
+       case CTS_POSTAL_VAL_POBOX_STR:
+               if (postal->embedded) {
+                       FREEandSTRDUP(postal->pobox, strval);
+               }
+               else
+                       postal->pobox = strval;
+               break;
+       case CTS_POSTAL_VAL_POSTALCODE_STR:
+               if (postal->embedded) {
+                       FREEandSTRDUP(postal->postalcode, strval);
+               }
+               else
+                       postal->postalcode = strval;
+               break;
+       case CTS_POSTAL_VAL_REGION_STR:
+               if (postal->embedded) {
+                       FREEandSTRDUP(postal->region, strval);
+               }
+               else
+                       postal->region = strval;
+               break;
+       case CTS_POSTAL_VAL_LOCALITY_STR:
+               if (postal->embedded) {
+                       FREEandSTRDUP(postal->locality, strval);
+               }
+               else
+                       postal->locality = strval;
+               break;
+       case CTS_POSTAL_VAL_STREET_STR:
+               if (postal->embedded) {
+                       FREEandSTRDUP(postal->street, strval);
+               }
+               else
+                       postal->street = strval;
+               break;
+       case CTS_POSTAL_VAL_EXTENDED_STR:
+               if (postal->embedded) {
+                       FREEandSTRDUP(postal->extended, strval);
+               }
+               else
+                       postal->extended = strval;
+               break;
+       case CTS_POSTAL_VAL_COUNTRY_STR:
+               if (postal->embedded) {
+                       FREEandSTRDUP(postal->country, strval);
+               }
+               else
+                       postal->country = strval;
+               break;
+       default:
+               ERR("Not supported field");
+               return CTS_ERR_ARG_INVALID;
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_company_set_str(
+               cts_company *com, int field, char *strval)
+{
+       switch (field)
+       {
+       case CTS_COMPANY_VAL_NAME_STR:
+               if (com->embedded) {
+                       FREEandSTRDUP(com->name, strval);
+               }
+               else
+                       com->name = strval;
+               break;
+       case CTS_COMPANY_VAL_DEPARTMENT_STR:
+               if (com->embedded) {
+                       FREEandSTRDUP(com->department, strval);
+               }
+               else
+                       com->department = strval;
+               break;
+       case CTS_COMPANY_VAL_JOB_TITLE_STR:
+               if (com->embedded) {
+                       FREEandSTRDUP(com->jot_title, strval);
+               }
+               else
+                       com->jot_title = strval;
+               break;
+       case CTS_COMPANY_VAL_ROLE_STR:
+               if (com->embedded) {
+                       FREEandSTRDUP(com->role, strval);
+               }
+               else
+                       com->role = strval;
+               break;
+       case CTS_COMPANY_VAL_ASSISTANT_NAME_STR:
+               if (com->embedded) {
+                       FREEandSTRDUP(com->assistant_name, strval);
+               }
+               else
+                       com->assistant_name = strval;
+               break;
+       default:
+               ERR("Not supported field");
+               return CTS_ERR_ARG_INVALID;
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_group_set_str(
+               cts_group *group, int field, char *strval)
+{
+       switch (field)
+       {
+       case CTS_GROUP_VAL_NAME_STR:
+               if (group->embedded) {
+                       FREEandSTRDUP(group->name, strval);
+               }
+               else
+                       group->name = strval;
+               break;
+       case CTS_GROUP_VAL_RINGTONE_STR:
+               if (group->embedded) {
+                       FREEandSTRDUP(group->ringtone_path, strval);
+               }
+               else
+                       group->ringtone_path = strval;
+               break;
+       default:
+               ERR("Not supported field");
+               return CTS_ERR_ARG_INVALID;
+       }
+       return CTS_SUCCESS;
+}
+
+static inline int cts_extend_set_str(cts_extend *extend, int field, char *strval)
+{
+       switch (field)
+       {
+       case CTS_EXTEND_VAL_DATA2_STR:
+               if (extend->embedded) {
+                       FREEandSTRDUP(extend->data2, strval);
+               }
+               else
+                       extend->data2 = strval;
+               break;
+       case CTS_EXTEND_VAL_DATA3_STR:
+               if (extend->embedded) {
+                       FREEandSTRDUP(extend->data3, strval);
+               }
+               else
+                       extend->data3 = strval;
+               break;
+       case CTS_EXTEND_VAL_DATA4_STR:
+               if (extend->embedded) {
+                       FREEandSTRDUP(extend->data4, strval);
+               }
+               else
+                       extend->data4 = strval;
+               break;
+       case CTS_EXTEND_VAL_DATA5_STR:
+               if (extend->embedded) {
+                       FREEandSTRDUP(extend->data5, strval);
+               }
+               else
+                       extend->data5 = strval;
+               break;
+       case CTS_EXTEND_VAL_DATA6_STR:
+               if (extend->embedded) {
+                       FREEandSTRDUP(extend->data6, strval);
+               }
+               else
+                       extend->data6 = strval;
+               break;
+       case CTS_EXTEND_VAL_DATA7_STR:
+               if (extend->embedded) {
+                       FREEandSTRDUP(extend->data7, strval);
+               }
+               else
+                       extend->data7 = strval;
+               break;
+       case CTS_EXTEND_VAL_DATA8_STR:
+               if (extend->embedded) {
+                       FREEandSTRDUP(extend->data8, strval);
+               }
+               else
+                       extend->data8 = strval;
+               break;
+       case CTS_EXTEND_VAL_DATA9_STR:
+               if (extend->embedded) {
+                       FREEandSTRDUP(extend->data9, strval);
+               }
+               else
+                       extend->data9 = strval;
+               break;
+
+       case CTS_EXTEND_VAL_DATA10_STR:
+               if (extend->embedded) {
+                       FREEandSTRDUP(extend->data10, strval);
+               }
+               else
+                       extend->data10 = strval;
+               break;
+       default:
+               ERR("Not supported field");
+               return CTS_ERR_ARG_INVALID;
+       }
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_value_set_str(CTSvalue *value, int field, const char *strval)
+{
+       char *str;
+
+       retv_if(NULL == value, CTS_ERR_ARG_NULL);
+
+       if (strval && *strval)
+               str = (char *)strval;
+       else
+               str = NULL;
+
+       switch (value->v_type)
+       {
+       case CTS_VALUE_BASIC:
+               ((cts_basic*)value)->type = CTS_BASIC_VAL_STR;
+               if (value->embedded)
+                       FREEandSTRDUP(((cts_basic*)value)->val.s, str);
+               else
+                       ((cts_basic*)value)->val.s = str;
+               break;
+       case CTS_VALUE_CONTACT_BASE_INFO:
+               return cts_base_set_str((cts_ct_base *)value, field, str);
+       case CTS_VALUE_NAME:
+               return cts_name_set_str((cts_name *)value, field, str);
+       case CTS_VALUE_POSTAL:
+               return cts_postal_set_str((cts_postal *)value, field, str);
+       case CTS_VALUE_COMPANY:
+               return cts_company_set_str((cts_company *)value, field, str);
+       case CTS_VALUE_GROUP:
+               return cts_group_set_str((cts_group *)value, field, str);
+       case CTS_VALUE_EXTEND:
+               return cts_extend_set_str((cts_extend *)value, field, str);
+       case CTS_VALUE_NUMBER:
+               retvm_if(CTS_NUM_VAL_NUMBER_STR != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               if (value->embedded)
+                       FREEandSTRDUP(((cts_number*)value)->number, str);
+               else
+                       ((cts_number *)value)->number = str;
+               break;
+       case CTS_VALUE_EMAIL:
+               retvm_if(CTS_EMAIL_VAL_ADDR_STR != field, CTS_ERR_ARG_INVALID, "Not supported field");
+               if (value->embedded)
+                       FREEandSTRDUP(((cts_email*)value)->email_addr, str);
+               else
+                       ((cts_email *)value)->email_addr = str;
+               break;
+       case CTS_VALUE_GROUP_RELATION:
+               retvm_if(CTS_GROUPREL_VAL_NAME_STR != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field(%d) for CTS_VALUE_GROUP_RELATION", field);
+               retvm_if(value->embedded, CTS_ERR_ARG_INVALID,
+                               "CTS_GROUPREL_VAL_NAME_STR is readonly");
+               ((cts_group *)value)->name = str;
+               break;
+       case CTS_VALUE_PHONELOG:  /* phonelog value never be embedded*/
+               if (CTS_PLOG_VAL_NUMBER_STR == field)
+                       ((cts_plog *)value)->number = str;
+               else if (CTS_PLOG_VAL_SHORTMSG_STR == field)
+                       ((cts_plog *)value)->extra_data2 = str;
+               else
+               {
+                       ERR("Not supported field");
+                       return CTS_ERR_ARG_INVALID;
+               }
+               break;
+       case CTS_VALUE_MESSENGER:
+               retvm_if(CTS_MESSENGER_VAL_IM_ID_STR != field, CTS_ERR_ARG_INVALID, "Not supported field");
+               if (value->embedded)
+                       FREEandSTRDUP(((cts_messenger *)value)->im_id, str);
+               else
+                       ((cts_messenger *)value)->im_id = str;
+               break;
+       case CTS_VALUE_WEB:
+               retvm_if(CTS_WEB_VAL_ADDR_STR != field, CTS_ERR_ARG_INVALID, "Not supported field");
+               if (value->embedded)
+                       FREEandSTRDUP(((cts_web *)value)->url, str);
+               else
+                       ((cts_web *)value)->url = str;
+               break;
+       case CTS_VALUE_NICKNAME:
+               retvm_if(CTS_NICKNAME_VAL_NAME_STR != field, CTS_ERR_ARG_INVALID, "Not supported field");
+               if (value->embedded)
+                       FREEandSTRDUP(((cts_nickname *)value)->nick, str);
+               else
+                       ((cts_nickname *)value)->nick = str;
+               break;
+       case CTS_VALUE_ADDRESSBOOK:
+               retvm_if(CTS_ADDRESSBOOK_VAL_NAME_STR != field, CTS_ERR_ARG_INVALID,
+                               "Not supported field");
+               if (value->embedded)
+                       FREEandSTRDUP(((cts_addrbook *)value)->name, str);
+               else
+                       ((cts_addrbook *)value)->name = str;
+               break;
+       case CTS_VALUE_EVENT:
+               /* evet value doesn't have string value */
+       default:
+               ERR("The value has unsupported type");
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       return CTS_SUCCESS;
+}
diff --git a/src/cts-struct.h b/src/cts-struct.h
new file mode 100755 (executable)
index 0000000..bd5b1db
--- /dev/null
@@ -0,0 +1,826 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_STRUCT_H__
+#define __CTS_STRUCT_H__
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <string.h>
+
+#define CTS_NUMBER_MAX_LEN 512
+
+#define SMART_STRDUP(src) (src && *src)?strdup(src):NULL
+#define SAFE_STRDUP(src) (src)?strdup(src):NULL
+#define FREEandSTRDUP(dest, src) \
+       do{ \
+               free(dest);\
+               if (src) dest = strdup(src);\
+               else dest = NULL; \
+       }while (0)
+
+enum {
+       CTS_HANDLE_STR_GET,
+       CTS_HANDLE_STR_STEAL,
+};
+
+#define HANDLE_STEAL_STRING(op_code, dest, src) \
+       do{ \
+               dest=src; \
+               if (CTS_HANDLE_STR_STEAL == op_code) src=NULL; \
+       }while (0)
+
+#define CTS_DATA_FIELD_NAME (1<<0)
+#define CTS_DATA_FIELD_POSTAL (1<<1)
+#define CTS_DATA_FIELD_MESSENGER (1<<2)
+#define CTS_DATA_FIELD_WEB (1<<3)
+#define CTS_DATA_FIELD_EVENT (1<<4)
+#define CTS_DATA_FIELD_COMPANY (1<<5)
+#define CTS_DATA_FIELD_NICKNAME (1<<6)
+#define CTS_DATA_FIELD_NUMBER (1<<7)
+#define CTS_DATA_FIELD_EMAIL (1<<8)
+#define CTS_DATA_FIELD_EXTEND_ALL (1<<9)
+#define CTS_DATA_FIELD_ALL ((1<<9)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0))
+
+enum {
+       CTS_DATA_NAME = 1,
+       CTS_DATA_POSTAL = 2,
+       CTS_DATA_MESSENGER = 3,
+       CTS_DATA_WEB = 4,
+       CTS_DATA_EVENT = 5,
+       CTS_DATA_COMPANY = 6,
+       CTS_DATA_NICKNAME = 7,
+       CTS_DATA_NUMBER = 8,
+       CTS_DATA_EMAIL = 9,
+       CTS_DATA_EXTEND_START = 100
+};
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       int type;
+       union {
+               int i;
+               bool b;
+               double d;
+               char *s;
+       }val;
+}cts_basic; //CTS_BASIC_VAL_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       bool uid_changed;
+       bool img_changed;
+       bool full_img_changed;
+       bool ringtone_changed;
+       bool note_changed;
+       bool is_favorite;
+       int id;
+       int changed_time;
+       int addrbook_id;
+       char *uid;
+       char *img_path;
+       char *full_img_path;
+       char *ringtone_path;
+       char *note;
+       char *vcard_img_path;
+}cts_ct_base; //CTS_BASE_VAL_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       bool is_changed;
+       int id;
+       int lang_type;
+       char *first;
+       char *last;
+       char *addition;
+       char *display;
+       char *prefix;
+       char *suffix;
+}cts_name; //CTS_NAME_VAL_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       bool is_default;
+       bool is_favorite;
+       int id;
+       int type;
+       char *number;
+       char *added_type;
+}cts_number; //CTS_NUM_VAL_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       bool is_default;
+       int id;
+       int type;
+       char *email_addr;
+}cts_email; //CTS_EMAIL_VAL_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       int id;
+       int type;
+       char *url;
+}cts_web; //CTS_WEB_VAL_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       bool is_default;
+       int id;
+       int type;
+       char *pobox;
+       char *postalcode;
+       char *region;
+       char *locality;
+       char *street;
+       char *extended;
+       char *country;
+}cts_postal; //CTS_POSTAL_VAL_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       int id;
+       int type;
+       int date;
+}cts_event;//CTS_EVENT_VAL_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       int id;
+       int type;
+       char *im_id;
+}cts_messenger;//CTS_MESSENGER_VAL_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       int id;
+       char *nick;
+}cts_nickname; //CTS_NICKNAME_VAL_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       int id;
+       int addrbook_id;
+       char *name;
+       char *ringtone_path;
+       char *vcard_group;
+       //   char *image_path;
+}cts_group; //CTS_GROUP_VAL_  or CTS_GROUPREL_VAL_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       int id;
+       int acc_id;
+       int acc_type;
+       int mode;
+       char *name;
+}cts_addrbook; //CTS_ADDRESSBOOK_VAL_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted; /* not used */
+       int id;
+       char *name;
+       char *department;
+       char *jot_title;
+       char *role;
+       char *assistant_name;
+}cts_company;//CTS_COMPANY_VAL_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       int id;
+       char *number;
+       int related_id; /* contact id */
+       int log_time;
+       int log_type;
+       int extra_data1; /* duration, message_id */
+       char *extra_data2; /*short message*/
+}cts_plog;//PHONELOGVALUE
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+       int id;
+       int type;
+       int data1;
+       char *data2;
+       char *data3;
+       char *data4;
+       char *data5;
+       char *data6;
+       char *data7;
+       char *data8;
+       char *data9;
+       char *data10;
+}cts_extend;//EXTENDVALUE
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       int id;
+       int num_type;
+       char *first;
+       char *last;
+       char *display;
+       char *number;
+       char *img_path;
+       int log_time;
+       int log_type;
+       int extra_data1; /* duration, message_id */
+       char *extra_data2; /*short message*/
+       int related_id; /* contact id */
+}plog_list;//CTS_LIST_PLOG_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       int id;
+       int acc_id;
+       char *img_path;
+       char *first;
+       char *last;
+       char *display;
+       char *connect;
+       char *normalize;
+}contact_list;//CTS_LIST_CONTACT_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       char *name;
+       char *number;
+}sdn_list;//SDNLIST
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       int changed_type:8;
+       int id;
+       int changed_ver;
+}change_list;//CTS_LIST_CHANGE_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       int id;
+       int account_type;
+       char *name;
+}addrbook_list;//CTS_LIST_ADDRESSBOOK_
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       int id;
+       char *name;
+}numtype_list;//CUSTOMNUMTYPELIST
+
+typedef struct {
+       int v_type:16;
+       bool embedded;
+       int id;
+       int contact_id;
+       char *first;
+       char *last;
+       char *display;
+       char *number;
+       char *img_path;
+       int num_type;
+       int speeddial;
+}shortcut_list;//CTS_LIST_FAVORITE_
+
+typedef struct {
+       int s_type;
+       cts_ct_base *base;
+       cts_name *name;
+       GSList *numbers;
+       GSList *emails;
+       GSList *grouprelations;
+       GSList *events;
+       GSList *messengers;
+       GSList *postal_addrs;
+       GSList *web_addrs;
+       GSList *nicknames;
+       cts_company *company;
+       int default_num;
+       int default_email;
+       GSList *extended_values;
+}contact_t; //cts_struct_field
+
+enum{
+       CTS_VALUE_BASIC = 100, /**< Deprecated */
+       CTS_VALUE_LIST_CONTACT = 101,
+       CTS_VALUE_LIST_ADDRBOOK, // ADDRESSBOOKLIST order must be same to ADDRESSBOOKVALUE order.
+       CTS_VALUE_LIST_PLOG,
+       CTS_VALUE_LIST_CUSTOM_NUM_TYPE,
+       CTS_VALUE_LIST_CHANGE,
+       CTS_VALUE_LIST_GROUP,
+       CTS_VALUE_LIST_NUMBERINFO, // NUMBERLIST order must be same to EMAILLIST order.
+       CTS_VALUE_LIST_EMAILINFO, // EMAILLIST order must be same to NUMBERLIST order.
+       CTS_VALUE_LIST_NUMS_EMAILS,
+       CTS_VALUE_LIST_SDN,
+       CTS_VALUE_RDONLY_NAME,
+       CTS_VALUE_RDONLY_NUMBER,
+       CTS_VALUE_RDONLY_EMAIL,
+       CTS_VALUE_RDONLY_COMPANY,
+       CTS_VALUE_LIST_SHORTCUT,
+       CTS_VALUE_RDONLY_PLOG,
+};
+
+//basic
+enum {
+       CTS_BASIC_VAL_INT,
+       CTS_BASIC_VAL_DBL,
+       CTS_BASIC_VAL_BOOL,
+       CTS_BASIC_VAL_STR
+};
+
+#ifndef __CONTACTS_SVC_H__
+
+struct cts_struct{
+       int s_type;
+};
+
+struct cts_value{
+       int v_type:16;
+       bool embedded;
+       bool deleted;
+};
+
+//<!--
+
+/**
+ * CTSstruct is an opaque type, it must be used via accessor functions.
+ * Conceptually, each Struct is a set of values and list of values.
+ *
+ * To remove a value from a list of values, set the VAL_DELETE
+ * field in the value and store the list.
+ *
+ * @see contacts_svc_struct_new(), contacts_svc_struct_free()
+ * @see contacts_svc_struct_get_value(), contacts_svc_struct_get_list(),
+ * @see contacts_svc_struct_store_value(), contacts_svc_struct_store_list()
+ */
+typedef struct cts_struct CTSstruct;
+
+/**
+ * CTSvalue is an opaque type, it must be
+ * used via accessor functions. Conceptually, each value is
+ * a tuple of fields with a fixed type per field, with each field
+ * accessed inside the value via a fixed index number (for example,
+ * #NAMEVALUE). Supported types are int (value range as in C int), string
+ * and boolean (C++ bool). The right access methods must be used depending
+ * on the field type.
+ *
+ * @see contacts_svc_value_new(), contacts_svc_value_free()
+ * @see contacts_svc_value_set_int(), contacts_svc_value_set_bool(), contacts_svc_value_set_str()
+ * @see contacts_svc_value_get_int(), contacts_svc_value_get_bool(), contacts_svc_value_get_str()
+ */
+typedef struct cts_value CTSvalue;
+
+
+//////////////////// Value ////////////////////
+/**
+ * Use for contacts_svc_value_new()
+ *
+ * Unless noted otherwise, these values are storded in a contact
+ * Struct. Some of those values may occur more than once per contact
+ * Struct. Those values are stored in lists, see #cts_struct_field.
+ */
+typedef enum
+{
+       CTS_VALUE_CONTACT_BASE_INFO,/**< #BASEVALUE */
+       CTS_VALUE_NAME,/**< #NAMEVALUE */
+       CTS_VALUE_NUMBER,/**< #NUMBERVALUE */
+       CTS_VALUE_EMAIL,/**< #EMAILVALUE */
+       CTS_VALUE_WEB,/**< #WEBVALUE */
+       CTS_VALUE_POSTAL,/**< #POSTALVALUE */
+       CTS_VALUE_EVENT,/**< #EVENTVALUE */
+       CTS_VALUE_MESSENGER,/**< #MESSENGERVALUE */
+       CTS_VALUE_GROUP_RELATION,/**< #GROUPRELATIONVALUE */
+       CTS_VALUE_COMPANY,/**< #COMPANYVALUE */
+       CTS_VALUE_PHONELOG,/**< #PHONELOGVALUE, not part of a contact, see contacts_svc_insert_phonelog() and friends */
+       CTS_VALUE_GROUP,/**< #GROUPVALUE, not part of a contact, see contacts_svc_insert_group() */
+       CTS_VALUE_EXTEND,/**< #EXTENDVALUE(@ref CONTACTS_SVC_EXTEND) */
+       CTS_VALUE_NICKNAME,/**< #NICKNAMEVALUE */
+       CTS_VALUE_ADDRESSBOOK /**< #ADDRESSBOOKVALUE, not part of a contact, see contacts_svc_insert_addressbook() */
+}cts_value_type;
+
+/**
+ * base information
+ */
+enum BASEVALUE {
+       CTS_BASE_VAL_ID_INT,/**< A contact index number. read only */
+       CTS_BASE_VAL_CHANGED_TIME_INT,/**< read only, The time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds.
+                                                                                         It is based on system. If system time is invalid, this value is invalid too.*/
+       CTS_BASE_VAL_IMG_PATH_STR, /**< A thumbnail image. Should include extension at path */
+       CTS_BASE_VAL_RINGTONE_PATH_STR, /**< .*/
+       CTS_BASE_VAL_NOTE_STR, /**< .*/
+       CTS_BASE_VAL_UID_STR, /**< A globally (including outside of the device) unique ID. */
+       CTS_BASE_VAL_ADDRESSBOOK_ID_INT, /**< read only. Each contact is assigned to a addressbook. */
+       CTS_BASE_VAL_FULL_IMG_PATH_STR, /**< For full screen image. Should include extension at path */
+       CTS_BASE_VAL_FAVORITE_BOOL /**< read only. Use contacts_svc_set_favorite(CTS_FAVOR_CONTACT). It can assign for handling struct. But the changes are ignored */
+};
+
+/**
+ * name
+ */
+enum NAMEVALUE {
+       CTS_NAME_VAL_FIRST_STR,/**< for example, John */
+       CTS_NAME_VAL_LAST_STR,/**< for example, Doe */
+       CTS_NAME_VAL_ADDITION_STR,/**< also known as "middle name(s)" */
+       CTS_NAME_VAL_SUFFIX_STR,/**< for example, Jr. for "Junior" */
+       CTS_NAME_VAL_PREFIX_STR,/**< for example, Mr. for "Mister" */
+       CTS_NAME_VAL_DISPLAY_STR,/**< see #CONTACTS_SVC_NAME */
+};
+
+/**
+ * A phone number
+ */
+enum NUMBERVALUE {
+       CTS_NUM_VAL_ID_INT,/**< read only, for use in contacts_svc_set_favorite(CTS_FAVOR_NUMBER) */
+       CTS_NUM_VAL_TYPE_INT,/**< you can use #NUMBERTYPE or contacts_svc_find_custom_type().*/
+       CTS_NUM_VAL_DEFAULT_BOOL,/**< */
+       CTS_NUM_VAL_FAVORITE_BOOL, /**< read only. Set with contacts_svc_set_favorite(CTS_FAVOR_NUMBER). It can assign for handling struct. But the changes are ignored */
+       CTS_NUM_VAL_DELETE_BOOL,/**< request to delete in the list of #CTSstruct. */
+       CTS_NUM_VAL_NUMBER_STR,/**< .*/
+};
+
+/**
+ * email
+ */
+enum EMAILVALUE {
+       CTS_EMAIL_VAL_ID_INT,/**< read only */
+       CTS_EMAIL_VAL_TYPE_INT,/**< #EMAILTYPE.*/
+       CTS_EMAIL_VAL_DEFAULT_BOOL,/**< */
+       CTS_EMAIL_VAL_DELETE_BOOL,/**< request to delete in the list of #CTSstruct. */
+       CTS_EMAIL_VAL_ADDR_STR,/**< .*/
+};
+
+/**
+ * group relation information for contact
+ */
+enum GROUPRELATIONVALUE {
+       CTS_GROUPREL_VAL_ID_INT, /**< [write only]group id */
+       CTS_GROUPREL_VAL_DELETE_BOOL,/**< request to delete in the list of #CTSstruct. */
+       CTS_GROUPREL_VAL_NAME_STR,/**< read only, but it can assign for handling struct(Not recommend) */
+       CTS_GROUPREL_VAL_RINGTONE_STR,/**< read only */
+       //   CTS_GROUPREL_VAL_IMG_PATH_STR,
+};
+
+/**
+ * event, for example birthday
+ */
+enum EVENTVALUE {
+       CTS_EVENT_VAL_TYPE_INT,/**< #EVENTTYPE*/
+       CTS_EVENT_VAL_DELETE_BOOL,/**< request to delete in the list of #CTSstruct. */
+       CTS_EVENT_VAL_DATE_INT,/**< The date(YYYYMMDD). ex) 20100107 : year = 2010, month = 01, day = 07 */
+};
+
+/**
+ * web address
+ */
+enum WEBVALUE {
+       CTS_WEB_VAL_TYPE_INT,/**< #WEBTYPE */
+       CTS_WEB_VAL_DELETE_BOOL,/**< request to delete in the list of #CTSstruct. */
+       CTS_WEB_VAL_ADDR_STR,/**< .*/
+};
+
+/**
+ * postal address
+ */
+enum POSTALVALUE {
+       CTS_POSTAL_VAL_TYPE_INT,/**< #ADDRESSTYPE*/
+       CTS_POSTAL_VAL_DELETE_BOOL,/**< request to delete in the list of #CTSstruct. */
+       CTS_POSTAL_VAL_POBOX_STR,/**< .*/
+       CTS_POSTAL_VAL_POSTALCODE_STR,/**< .*/
+       CTS_POSTAL_VAL_REGION_STR,/**< e.g., state or province */
+       CTS_POSTAL_VAL_LOCALITY_STR,/**< e.g., city */
+       CTS_POSTAL_VAL_STREET_STR,/**< .*/
+       CTS_POSTAL_VAL_EXTENDED_STR,/**< .*/
+       CTS_POSTAL_VAL_COUNTRY_STR,/**< .*/
+       CTS_POSTAL_VAL_DEFAULT_BOOL,/**< */
+};
+
+/**
+ * messenger
+ */
+enum MESSENGERVALUE {
+       CTS_MESSENGER_VAL_TYPE_INT,/**< #cts_im_type */
+       CTS_MESSENGER_VAL_DELETE_BOOL,/**< request to delete in the list of #CTSstruct. */
+       CTS_MESSENGER_VAL_IM_ID_STR,/**< .*/
+};
+
+/**
+ * company
+ */
+enum COMPANYVALUE {
+       CTS_COMPANY_VAL_NAME_STR,/**< .*/
+       CTS_COMPANY_VAL_DEPARTMENT_STR,/**< .*/
+       CTS_COMPANY_VAL_JOB_TITLE_STR,/**< .*/
+       CTS_COMPANY_VAL_ASSISTANT_NAME_STR,/**< .*/
+       CTS_COMPANY_VAL_ROLE_STR,/**< .*/
+};
+
+/**
+ * nickname
+ */
+enum NICKNAMEVALUE {
+       CTS_NICKNAME_VAL_DELETE_BOOL,/**< request to delete in the list of #CTSstruct. */
+       CTS_NICKNAME_VAL_NAME_STR,/**< .*/
+};
+
+/**
+ * phone log
+ */
+enum PHONELOGVALUE {
+       CTS_PLOG_VAL_NUMBER_STR,/**< .*/
+       CTS_PLOG_VAL_ID_INT,/**< read only */
+       CTS_PLOG_VAL_LOG_TIME_INT,/**< The time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds.*/
+       CTS_PLOG_VAL_LOG_TYPE_INT,/**< #PLOGTYPE */
+       CTS_PLOG_VAL_DURATION_INT,/**< seconds. */
+       CTS_PLOG_VAL_SHORTMSG_STR,/**< . */
+       CTS_PLOG_VAL_MSGID_INT,/**< . */
+       CTS_PLOG_VAL_RELATED_ID_INT,/**< contact id */
+};
+
+/**
+ * group
+ */
+enum GROUPVALUE {
+       CTS_GROUP_VAL_ID_INT, /**< read only */
+       CTS_GROUP_VAL_ADDRESSBOOK_ID_INT, /**< . */
+       CTS_GROUP_VAL_NAME_STR,/**< . */
+       CTS_GROUP_VAL_RINGTONE_STR,/**< . */
+};
+
+/**
+ * addressbook
+ */
+enum ADDRESSBOOKVALUE
+{
+       CTS_ADDRESSBOOK_VAL_ID_INT, /**< read only */
+       CTS_ADDRESSBOOK_VAL_NAME_STR, /**< . */
+       CTS_ADDRESSBOOK_VAL_ACC_ID_INT, /**< The related account id */
+       CTS_ADDRESSBOOK_VAL_ACC_TYPE_INT, /**< #ADDRESSBOOKTYPE */
+       CTS_ADDRESSBOOK_VAL_MODE_INT, /**< #ADDRESSBOOKPERMISSION
+                                                                                         It is only data. nothing to do in contacts-service */
+};
+
+/**
+ * extended value
+ * @ref CONTACTS_SVC_EXTEND
+ *
+ * See #CTS_TYPE_CLASS_EXTEND_DATA, contacts_svc_find_custom_type().
+ */
+enum EXTENDVALUE {
+       CTS_EXTEND_VAL_DELETE_BOOL,/**< request to delete in the list of #CTSstruct. */
+       CTS_EXTEND_VAL_DATA1_INT,/**< . */
+       CTS_EXTEND_VAL_DATA2_STR,/**< . */
+       CTS_EXTEND_VAL_DATA3_STR,/**< . */
+       CTS_EXTEND_VAL_DATA4_STR,/**< . */
+       CTS_EXTEND_VAL_DATA5_STR,/**< . */
+       CTS_EXTEND_VAL_DATA6_STR,/**< . */
+       CTS_EXTEND_VAL_DATA7_STR,/**< . */
+       CTS_EXTEND_VAL_DATA8_STR,/**< . */
+       CTS_EXTEND_VAL_DATA9_STR,/**< . */
+       CTS_EXTEND_VAL_DATA10_STR,/**< . */
+};
+
+
+//////////////////// Struct ////////////////////
+/**
+ * Use for contacts_svc_struct_new()
+ */
+typedef enum {
+       CTS_STRUCT_CONTACT = 0, /**< CTS_STRUCT_CONTACT */
+}cts_struct_type;
+
+/**
+ * Contacts service struct fields
+ * CF means Contact Field. Some of these
+ * fields may only have one value (_VALUE suffix),
+ * others have a list of values (_LIST suffix).
+ */
+typedef enum
+{
+       CTS_CF_NONE,/**< CTS_CF_NONE */
+       CTS_CF_BASE_INFO_VALUE,/**< #BASEVALUE */
+       CTS_CF_NAME_VALUE,/**< #NAMEVALUE */
+       CTS_CF_COMPANY_VALUE,/**< #COMPANYVALUE */
+       CTS_CF_VALUE_MAX,/**< CTS_CF_VALUE_MAX */
+       CTS_CF_NUMBER_LIST,/**< List of #NUMBERVALUE */
+       CTS_CF_EMAIL_LIST,/**< List of #EMAILVALUE */
+       CTS_CF_GROUPREL_LIST,/**< List of #GROUPVALUE */
+       CTS_CF_EVENT_LIST,/**< List of #EVENTVALUE */
+       CTS_CF_MESSENGER_LIST,/**< List of #MESSENGERVALUE */
+       CTS_CF_POSTAL_ADDR_LIST,/**< List of #POSTALVALUE */
+       CTS_CF_WEB_ADDR_LIST,/**< List of #WEBVALUE */
+       CTS_CF_NICKNAME_LIST,/**< List of #NICKNAMEVALUE */
+       CTS_CF_FIELD_MAX,/**< CTS_CF_FIELD_MAX */
+}cts_struct_field;
+
+/**
+ * Allocate, initialize and return a new contacts service struct.
+ *
+ * @param[in] type The type of contacts service struct
+ * @return The pointer of New contacts service struct, NULL on error
+ * @see contacts_svc_struct_free()
+ */
+CTSstruct* contacts_svc_struct_new(cts_struct_type type);
+
+/**
+ * A destructor for contacts service struct.
+ *
+ * @param[in] structure A contacts service struct
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @see contacts_svc_struct_new()
+ */
+int contacts_svc_struct_free(CTSstruct* structure);
+
+/**
+ * This function gets the contacts service value of a single-value field(_VALUE suffix) in the contacts service struct.
+ * Must not be used with fields which contain a list(_LIST suffix).
+ *
+ * @param[in] structure A contacts service struct
+ * @param[in] field The index of the contacts service value in contacts service struct.
+ * @param[out] retval the contacts service value requested with field(should not be freed)
+ * @return     #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_struct_get_value(CTSstruct *structure, cts_struct_field field, CTSvalue** retval);
+
+/**
+ * This function sets the contacts service value of a single-value field(_VALUE suffix) in the contacts service struct.
+ * \n For efficiency, Ownership of the contacts service value is transferred to the contacts service struct.
+ * (Although values be free by contacts_svc_value_free, it is ignored automatically)
+ * But string values of contacts service value are copied, and thus ownership of the original string
+ * remains with the original creator of it.
+ *
+ * @param[in] structure A contacts service struct
+ * @param[in] field The index of the contacts service value in contacts service struct.
+ * @param[in] value the contacts service value to be set
+ * @return     #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_struct_store_value(CTSstruct *structure, cts_struct_field field, CTSvalue* value);
+
+/**
+ * This function gets the pointer to a glib singly-linked list holding all values of multi-value field(_LIST suffix) in the contacts service struct.
+ * Must not be used with single-value fields.
+ *
+ * @param[in] structure A contacts service struct
+ * @param[in] field The index of the glib singly-linked list in contacts service struct.
+ * @param[out] retlist the glib singly-linked list requested with field(should not be freed or removed)
+ * @return     #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_struct_get_list(CTSstruct *structure, cts_struct_field field, GSList** retlist);
+
+/**
+ * This function sets the glib singly-linked list to the contacts service struct.
+ * \n The list is copied.(list is needed to free)
+ * But values(#CTSvalue) of the list are moved to the contacts service struct for efficiency.
+ * (Although values be free by contacts_svc_value_free, it is ignored automatically)
+ *
+ * @param[in] structure A contacts service struct
+ * @param[in] field The index of the glib singly-linked list in contacts service struct.
+ * @param[in] list the glib singly-linked list to be set
+ * @return     #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_struct_store_list(CTSstruct *structure, cts_struct_field field, GSList* list);
+
+/**
+ * Allocate, initialize and return a new contacts service value.
+ * @param[in] type The type of contacts service value
+ * @return The pointer of New contacts service value, NULL on error
+ * @see contacts_svc_value_free()
+ */
+CTSvalue* contacts_svc_value_new(cts_value_type type);
+
+/**
+ * A destructor for contacts service value.
+ * If it is in struct, this function will ignore to free and return #CTS_ERR_ARG_INVALID.
+ * @param[in] value A contacts service value
+ * @return     #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @see contacts_svc_value_new()
+ */
+int contacts_svc_value_free(CTSvalue* value);
+
+/**
+ * This function sets integer field in the contacts service value.
+ * May only be used with fields of type integer (_INT suffix in enum).
+ *
+ * @param[in] value The contacts service value
+ * @param[in] field The index of the integer field in the contacts service value.
+ * @param[in] intval The integer value to be set.
+ * @return     #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_value_set_int(CTSvalue* value, int field, int intval);
+
+/**
+ * This function sets boolean field in the contacts service value.
+ * May only be used with fields of type boolean (_BOOL suffix in enum).
+ *
+ * @param[in] value The contacts service value
+ * @param[in] field The index of the boolean field in the contacts service value.
+ * @param[in] boolval The boolean value to be set.
+ * @return     #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_value_set_bool(CTSvalue* value, int field, bool boolval);
+
+/**
+ * This function sets string field in the contacts service value.(call by reference)
+ * May only be used with fields of type string (_STR suffix in enum).
+ * \n If it is in struct, free old string and copy strval to struct.(call by value)
+ * \n empty string is handled as NULL and thus will result in NULL being stored
+ * @param[in] value The contacts service value
+ * @param[in] field The index of the string field in the contacts service value.
+ * @param[in] strval The string value to be set.
+ * @return     #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_value_set_str(CTSvalue* value, int field, const char *strval);
+
+/**
+ * This function gets the type of the contacts service value.
+ * @param[in] value The contacts service value
+ * @return Value Type(#cts_value_type) on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_value_get_type(CTSvalue* value);
+
+/**
+ * This function gets the pointer to a string field of the contacts service value.
+ * May only be used with fields of type string (_STR suffix in enum).
+ *
+ * @param[in] value The contacts service value
+ * @param[in] field The index of the string field in the contacts service value.
+ * @return string value(should not be freed, never empty), or NULL if no value is obtained
+ */
+const char* contacts_svc_value_get_str(CTSvalue *value, int field);
+
+/**
+ * This function gets boolean value of a field in the contacts service value.
+ * May only be used with fields of type boolean (_BOOL suffix in enum).
+ *
+ * @param[in] value The contacts service value
+ * @param[in] field The index of the boolean field in the contacts service value.
+ * @return boolean value, or false if no value is obtained
+ */
+bool contacts_svc_value_get_bool(CTSvalue* value, int field);
+
+/**
+ * This function gets Integer value of the contacts service value.
+ * May only be used with fields of type integer (_INT suffix in enum).
+ * @param[in] value The contacts service value
+ * @param[in] field The index of the integer field in the contacts service value.
+ * @return Integer value, or 0 if no value is obtained
+ */
+int contacts_svc_value_get_int(CTSvalue* value, int field);
+
+//-->
+#endif //__CONTACTS_SVC_H__
+
+#endif //__CTS_STRUCT_H__
+
diff --git a/src/cts-types.c b/src/cts-types.c
new file mode 100755 (executable)
index 0000000..0cab02f
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "cts-internal.h"
+#include "cts-sqlite.h"
+#include "cts-schema.h"
+#include "cts-utils.h"
+#include "cts-types.h"
+
+API char* contacts_svc_get_custom_type(cts_custom_type_class type_class,
+               int index)
+{
+       int ret;
+       char *ret_val = NULL;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MIN_LEN] = {0};
+
+       CTS_START_TIME_CHECK;
+
+       if (CTS_TYPE_CLASS_EXTEND_DATA == type_class) index -= CTS_DATA_EXTEND_START;
+       else if (CTS_TYPE_CLASS_NUM == type_class) index ^= CTS_NUM_TYPE_CUSTOM;
+
+       snprintf(query, sizeof(query),
+                       "SELECT name FROM %s WHERE id = %d",
+                       CTS_TABLE_CUSTOM_TYPES, index);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, NULL, "cts_query_prepare() Failed");
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE == ret)
+               ret_val = cts_stmt_get_text(stmt, 0);
+       cts_stmt_finalize(stmt);
+
+       ret_val = SAFE_STRDUP(ret_val);
+
+       CTS_END_TIME_CHECK();
+       return ret_val;
+}
+
+API int contacts_svc_insert_custom_type(cts_custom_type_class type_class,
+               char *type_name)
+{
+       int ret;
+       cts_stmt stmt = NULL;
+       char query[CTS_SQL_MIN_LEN] = {0};
+
+       retv_if(NULL == type_name, CTS_ERR_ARG_NULL);
+
+       snprintf(query, sizeof(query),
+                       "INSERT INTO %s(class, name) VALUES(%d, ?)",
+                       CTS_TABLE_CUSTOM_TYPES, type_class);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       cts_stmt_bind_text(stmt, 1, type_name);
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+       ret = cts_db_get_last_insert_id();
+       cts_stmt_finalize(stmt);
+
+       int trans_ret = contacts_svc_end_trans(true);
+       retvm_if(trans_ret < CTS_SUCCESS, trans_ret,
+                       "contacts_svc_end_trans(true) Failed(%d)", trans_ret);
+
+       if (CTS_TYPE_CLASS_EXTEND_DATA == type_class) ret += CTS_DATA_EXTEND_START;
+       else if (CTS_TYPE_CLASS_NUM == type_class) ret |= CTS_NUM_TYPE_CUSTOM;
+       return ret;
+}
+
+API int contacts_svc_delete_custom_type(cts_custom_type_class type_class,
+               int index)
+{
+       int ret;
+       char  query[CTS_SQL_MIN_LEN] = {0};
+
+       retvm_if(CTS_TYPE_CLASS_NUM == type_class && index <= CTS_NUM_TYPE_ASSISTANT,
+                       CTS_ERR_ARG_INVALID,
+                       "This custom number type(System Number Type) is diable to delete");
+
+       if (CTS_TYPE_CLASS_EXTEND_DATA == type_class) index -= CTS_DATA_EXTEND_START;
+       else if (CTS_TYPE_CLASS_NUM == type_class) index ^= CTS_NUM_TYPE_CUSTOM;
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       snprintf(query, sizeof(query), "DELETE FROM %s WHERE class = %d AND id = %d",
+                       CTS_TABLE_CUSTOM_TYPES, type_class, index);
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_find_custom_type(cts_custom_type_class type_class,
+               char *type_name)
+{
+       int ret;
+       char query[CTS_SQL_MAX_LEN] = {0};
+
+       retv_if(NULL == type_name, CTS_ERR_ARG_NULL);
+
+       CTS_START_TIME_CHECK;
+
+       snprintf(query, sizeof(query),
+                       "SELECT id FROM %s WHERE class = %d AND name = '%s'",
+                       CTS_TABLE_CUSTOM_TYPES, type_class, type_name);
+       ret = cts_query_get_first_int_result(query);
+       retvm_if(ret < CTS_SUCCESS, ret, "cts_query_get_first_int_result() Failed(%d)", ret);
+
+       if (CTS_TYPE_CLASS_EXTEND_DATA == type_class) ret += CTS_DATA_EXTEND_START;
+       else if (CTS_TYPE_CLASS_NUM == type_class) ret |= CTS_NUM_TYPE_CUSTOM;
+
+       CTS_END_TIME_CHECK();
+       return ret;
+}
+
diff --git a/src/cts-types.h b/src/cts-types.h
new file mode 100755 (executable)
index 0000000..6e81b8f
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_TYPES_H__
+#define __CTS_TYPES_H__
+
+//<!--
+/**
+ * @defgroup   CONTACTS_SVC_TYPES Types
+ * @ingroup    CONTACTS_SVC
+ * @addtogroup CONTACTS_SVC_TYPES
+ * @{
+ *
+ * It is Types of Number, E-mail, Web address, Address, Event, Phone Log, etc.
+ * And this interface provides methods to handle custom types.
+ *
+ */
+
+/**
+ * The Number can be made with a set of values by specifying one or more values.
+ * \n Example : CTS_NUM_TYPE_HOME|CTS_NUM_TYPE_VOICE
+ * \n Exceptionally, CTS_NUM_TYPE_CUSTOM is exclusive.
+ * CTS_NUM_TYPE_CUSTOM should be handled earlier.
+ */
+enum NUMBERTYPE{
+       CTS_NUM_TYPE_NONE = 0,
+       CTS_NUM_TYPE_HOME = 1<<0,/**< a telephone number associated with a residence */
+       CTS_NUM_TYPE_WORK = 1<<1,/**< a telephone number associated with a place of work */
+       CTS_NUM_TYPE_VOICE = 1<<2,/**< a voice telephone number */
+       CTS_NUM_TYPE_FAX = 1<<3,/**< a facsimile telephone number */
+       CTS_NUM_TYPE_MSG = 1<<4,/**< the telephone number has voice messaging support */
+       CTS_NUM_TYPE_CELL = 1<<5,/**< a cellular telephone number */
+       CTS_NUM_TYPE_PAGER = 1<<6,/**< a paging device telephone number */
+       CTS_NUM_TYPE_BBS = 1<<7,/**< a bulletin board system telephone number */
+       CTS_NUM_TYPE_MODEM = 1<<8,/**< a MODEM connected telephone number */
+       CTS_NUM_TYPE_CAR = 1<<9,/**< a car-phone telephone number */
+       CTS_NUM_TYPE_ISDN = 1<<10,/**< an ISDN service telephone number */
+       CTS_NUM_TYPE_VIDEO = 1<<11,/**< a video conferencing telephone number */
+       CTS_NUM_TYPE_PCS = 1<<12,/**< a personal communication services telephone number */
+
+       CTS_NUM_TYPE_ASSISTANT = 1<<30,/**< a additional type for assistant */
+       CTS_NUM_TYPE_CUSTOM = 1<<31,/**< Custom number type */
+};
+
+enum EMAILTYPE{
+       CTS_EMAIL_TYPE_NONE = 0,/**< Other */
+       CTS_EMAIL_TYPE_HOME = 1<<0,/**< . */
+       CTS_EMAIL_TYPE_WORK = 1<<1,/**< . */
+};
+
+enum ADDRESSTYPE{
+       CTS_ADDR_TYPE_NONE = 0,/**< . */
+       CTS_ADDR_TYPE_HOME = 1<<0,/**< a delivery address for a residence */
+       CTS_ADDR_TYPE_WORK = 1<<1,/**< a delivery address for a place of work */
+       CTS_ADDR_TYPE_DOM = 1<<2,/**< a domestic delivery address */
+       CTS_ADDR_TYPE_INTL = 1<<3,/**< an international delivery address */
+       CTS_ADDR_TYPE_POSTAL = 1<<4,/**< a postal delivery address */
+       CTS_ADDR_TYPE_PARCEL = 1<<5,/**< a parcel delivery address */
+};
+
+enum WEBTYPE{
+       CTS_WEB_TYPE_NONE,/**< Other */
+       CTS_WEB_TYPE_HOME,/**< . */
+       CTS_WEB_TYPE_WORK,/**< . */
+};
+
+enum PLOGTYPE{
+       CTS_PLOG_TYPE_NONE,
+       CTS_PLOG_TYPE_VOICE_INCOMMING = 1,/**< . */
+       CTS_PLOG_TYPE_VOICE_OUTGOING = 2,/**< . */
+       CTS_PLOG_TYPE_VIDEO_INCOMMING = 3,/**< . */
+       CTS_PLOG_TYPE_VIDEO_OUTGOING = 4,/**< . */
+       CTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN = 5,/**< Not confirmed missed call */
+       CTS_PLOG_TYPE_VOICE_INCOMMING_SEEN = 6,/**< Confirmed missed call */
+       CTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN = 7,/**< Not confirmed missed video call */
+       CTS_PLOG_TYPE_VIDEO_INCOMMING_SEEN = 8,/**< Confirmed missed video call */
+       CTS_PLOG_TYPE_VOICE_REJECT = 9,/**< . */
+       CTS_PLOG_TYPE_VIDEO_REJECT = 10,/**< . */
+       CTS_PLOG_TYPE_VOICE_BLOCKED = 11,/**< . */
+       CTS_PLOG_TYPE_VIDEO_BLOCKED = 12,/**< . */
+
+       CTS_PLOG_TYPE_MMS_INCOMMING = 101,/**< . */
+       CTS_PLOG_TYPE_MMS_OUTGOING = 102,/**< . */
+       CTS_PLOG_TYPE_SMS_INCOMMING = 103,/**< . */
+       CTS_PLOG_TYPE_SMS_OUTGOING = 104,/**< . */
+       CTS_PLOG_TYPE_SMS_BLOCKED = 105,/**< . */
+       CTS_PLOG_TYPE_MMS_BLOCKED = 106,/**< . */
+       CTS_PLOG_TYPE_MAX
+};
+
+enum EVENTTYPE{
+       CTS_EVENT_TYPE_BIRTH,/**< . */
+       CTS_EVENT_TYPE_ANNIVERSARY/**< . */
+};
+
+enum ADDRESSBOOKTYPE{
+       CTS_ADDRESSBOOK_TYPE_INTERNAL, /**< . */
+       CTS_ADDRESSBOOK_TYPE_EXCHANGE, /**< . */
+       CTS_ADDRESSBOOK_TYPE_GOOGLE, /**< . */
+       CTS_ADDRESSBOOK_TYPE_YAHOO, /**< . */
+       CTS_ADDRESSBOOK_TYPE_FACEBOOK, /**< . */
+       CTS_ADDRESSBOOK_TYPE_OTHER, /**< . */
+};
+
+/**
+ * Use for contacts_svc_insert_custom_type(),
+ * contacts_svc_delete_custom_type(), contacts_svc_find_custom_type().
+ */
+typedef enum {
+       CTS_TYPE_CLASS_EXTEND_DATA=0,/**< Extend Data type(@ref CONTACTS_SVC_EXTEND) */
+       CTS_TYPE_CLASS_NUM=1,/**< Custom Number type */
+}cts_custom_type_class;
+
+/**
+ * This function inserts a User defined type into database.
+ * This api assigns a index of the group automatically.
+ * \n The returned index is unique & non-reusable.
+ *
+ * @param[in] type_class #cts_custom_type_class
+ * @param[in] type_name Name of Custom Type
+ * @return the index of the inserted custom type on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_insert_custom_type(cts_custom_type_class type_class, char *type_name);
+
+/**
+ * This function deletes a user defined type in database.
+ *
+ * @param[in] type_class #cts_custom_type_class
+ * @param[in] index The index of User defined type to delete in database.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_delete_custom_type(cts_custom_type_class type_class, int index);
+
+
+/**
+ * This function gets name of custom type.
+ * Obtained string should be free using by free().
+ * @param[in] type_class #cts_custom_type_class
+ * @param[in] index The index of User defined type.
+ * @return The gotten information, or NULL if no value is obtained or error
+ */
+char* contacts_svc_get_custom_type(cts_custom_type_class type_class, int index);
+
+/**
+ * This function gets index of user defined type of #name.
+ *
+ * @param[in] type_class #cts_custom_type_class
+ * @param[in] type_name The name of type for searching
+ * @return index of found Custom type on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_find_custom_type(cts_custom_type_class type_class, char *type_name);
+
+/*
+ * @}
+ */
+
+/**
+ * @defgroup   CONTACTS_SVC_EXTEND Using the Extend Data for Contact
+ * @ingroup    CONTACTS_SVC_STRUCT
+ * @addtogroup CONTACTS_SVC_EXTEND
+ * @{
+ *
+ * This is description of usages of extend data related with a contact.
+ *
+ * @section extend_sec1 Properties
+ * - The extend data is contacts service value(#CTSvalue).
+ * - The extend data only exist for contact struct(#CTSstruct).
+ * - The type of extend data is defined
+ * by contacts_svc_insert_custom_type() with #CTS_TYPE_CLASS_EXTEND_DATA.
+ * - The extend data is stored to contact by contacts_svc_struct_store_value().
+ * - Extend data can be stored only one at each type in contacts.
+ * - The index of custom type is used as the field parameter of contacts_svc_struct_store_value().
+ * - The composition of the extend data(#EXTENDVALUE)
+ *   -# #CTS_EXTEND_VAL_DATA1_INT
+ *   -# #CTS_EXTEND_VAL_DATA2_STR
+ *   -# #CTS_EXTEND_VAL_DATA3_STR
+ *   -# #CTS_EXTEND_VAL_DATA4_STR
+ *   -# #CTS_EXTEND_VAL_DATA5_STR
+ *   -# #CTS_EXTEND_VAL_DATA6_STR
+ *   -# #CTS_EXTEND_VAL_DATA7_STR
+ *   -# #CTS_EXTEND_VAL_DATA8_STR
+ *   -# #CTS_EXTEND_VAL_DATA9_STR
+ *   -# #CTS_EXTEND_VAL_DATA10_STR
+ *
+ * @section extend_sec2 Usages
+ * - Notice
+ * \n The extend data has values of fixed type.
+ * \n Therefore if you want to save values of the other types, convert to string.
+ * \n This mechanism is a supplementary mechanism. Do not abuse.
+ * - example
+ * @code
+ #include <stdio.h>
+ #include <glib.h>
+ #include <contacts-svc.h>
+
+ static void print_extend_contact(CTSstruct *contact)
+ {
+    int ret;
+    CTSvalue *value;
+    GSList *get_list, *cursor;
+    value = NULL;
+    contacts_svc_struct_get_value(contact, CTS_CF_NAME_VALUE, &value);
+    printf("First Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_FIRST_STR));
+    printf("Last Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_LAST_STR));
+
+    value = NULL;
+    ret = contacts_svc_find_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "YomiName");
+    ret = contacts_svc_struct_get_value(contact, ret, &value);
+    if(CTS_SUCCESS == ret) {
+       printf("extend1 data2 : %s\n", contacts_svc_value_get_str(value, CTS_EXTEND_VAL_DATA2_STR));
+       printf("extend1 data3 : %s\n", contacts_svc_value_get_str(value, CTS_EXTEND_VAL_DATA3_STR));
+       printf("extend1 data4 : %s\n", contacts_svc_value_get_str(value, CTS_EXTEND_VAL_DATA4_STR));
+    }
+    value = NULL;
+    ret = contacts_svc_find_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "Family");
+    ret = contacts_svc_struct_get_value(contact, ret, &value);
+    if(CTS_SUCCESS == ret) {
+       printf("extend2 data2 : %s\n", contacts_svc_value_get_str(value, CTS_EXTEND_VAL_DATA2_STR));
+       printf("extend2 data3 : %s\n", contacts_svc_value_get_str(value, CTS_EXTEND_VAL_DATA3_STR));
+       printf("extend2 data4 : %s\n", contacts_svc_value_get_str(value, CTS_EXTEND_VAL_DATA4_STR));
+    }
+    get_list = NULL;
+    contacts_svc_struct_get_list(contact, CTS_CF_NUMBER_LIST, &get_list);
+
+    cursor = get_list;
+    for(;cursor;cursor=g_slist_next(cursor))
+    {
+       printf("number Type = %d",
+          contacts_svc_value_get_int(cursor->data, CTS_NUM_VAL_TYPE_INT));
+       if(contacts_svc_value_get_bool(cursor->data, CTS_NUM_VAL_FAVORITE_BOOL))
+          printf("(favorite)");
+       printf("Number = %s\n",
+          contacts_svc_value_get_str(cursor->data, CTS_NUM_VAL_NUMBER_STR));
+    }
+ }
+
+ void extend_data_test(void)
+ {
+    int ret, index;
+    CTSstruct *contact;
+    CTSvalue *name, *number1, *extend_value;
+    GSList *numbers=NULL;
+
+    contact = contacts_svc_struct_new(CTS_STRUCT_CONTACT);
+
+    name = contacts_svc_value_new(CTS_VALUE_NAME);
+    if(name) {
+       contacts_svc_value_set_str(name, CTS_NAME_VAL_FIRST_STR, "People");
+       contacts_svc_value_set_str(name, CTS_NAME_VAL_LAST_STR, "Japan");
+    }
+    contacts_svc_struct_store_value(contact, CTS_CF_NAME_VALUE, name);
+    contacts_svc_value_free(name);
+
+    number1 = contacts_svc_value_new(CTS_VALUE_NUMBER);
+    if(number1) {
+       contacts_svc_value_set_str(number1, CTS_NUM_VAL_NUMBER_STR, "0333333333");
+       contacts_svc_value_set_int(number1, CTS_NUM_VAL_TYPE_INT, CTS_NUM_TYPE_MOBILE);
+       contacts_svc_value_set_bool(number1, CTS_NUM_VAL_DEFAULT_BOOL, true);
+    }
+    numbers = g_slist_append(numbers, number1);
+
+    contacts_svc_struct_store_list(contact, CTS_CF_NUMBER_LIST, numbers);
+    contacts_svc_value_free(number1);
+    g_slist_free(numbers);
+
+    extend_value = contacts_svc_value_new(CTS_VALUE_EXTEND);
+    if(extend_value) {
+       contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA2_STR, "YomiFirstName");
+       contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA3_STR, "YomiLastName");
+       contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA4_STR, "YomiCompanyName");
+    }
+    ret = contacts_svc_find_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "YomiName");
+    if(CTS_ERR_DB_RECORD_NOT_FOUND == ret)
+       ret = contacts_svc_insert_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "YomiName");
+    contacts_svc_struct_store_value(contact, ret, extend_value);
+    contacts_svc_value_free(extend_value);
+
+    extend_value = contacts_svc_value_new(CTS_VALUE_EXTEND);
+    if(extend_value) {
+       contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA2_STR, "Children1");
+       contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA3_STR, "Children2");
+       contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA4_STR, "Children3");
+    }
+    ret = contacts_svc_find_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "Family");
+    if(CTS_ERR_DB_RECORD_NOT_FOUND == ret)
+       ret = contacts_svc_insert_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "Family");
+    contacts_svc_struct_store_value(contact, ret, extend_value);
+    contacts_svc_value_free(extend_value);
+
+    index = contacts_svc_insert_contact(0, contact);
+    contacts_svc_struct_free(contact);
+    contact = NULL;
+
+    ret = contacts_svc_get_contact(index, &contact);
+    if(ret < 0)
+    {
+       printf("No found record\n");
+       return;
+    }
+    print_extend_contact(contact);
+
+    //update test
+
+    extend_value = NULL;
+    ret = contacts_svc_find_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "Family");
+    ret = contacts_svc_struct_get_value(contact, ret, &extend_value);
+    if(CTS_SUCCESS == ret)
+       contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA2_STR, "Children4");
+    contacts_svc_struct_store_value(contact, ret, extend_value);
+
+    contacts_svc_update_contact(contact);
+    contacts_svc_struct_free(contact);
+    contact = NULL;
+
+    ret = contacts_svc_get_contact(index, &contact);
+    if(ret < 0)
+    {
+       printf("No found record\n");
+       return;
+    }
+    print_extend_contact(contact);
+    contacts_svc_struct_free(contact);
+ }
+
+ int main()
+ {
+    contacts_svc_connect();
+
+    extend_data_test();
+
+    contacts_svc_disconnect();
+
+    return 0;
+ }
+
+ * @endcode
+ *
+ * @}
+ */
+
+//-->
+
+#endif //__CTS_TYPES_H__
+
diff --git a/src/cts-utils.c b/src/cts-utils.c
new file mode 100755 (executable)
index 0000000..8bec57c
--- /dev/null
@@ -0,0 +1,929 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <sys/time.h>
+#include <vconf.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include "cts-internal.h"
+#include "cts-utils.h"
+#include "cts-schema.h"
+#include "cts-sqlite.h"
+#include "cts-socket.h"
+#include "cts-normalize.h"
+#include "cts-inotify.h"
+#include "cts-vcard.h"
+#include "cts-pthread.h"
+#include "cts-types.h"
+
+static const char *CTS_NOTI_CONTACT_CHANGED=CTS_NOTI_CONTACT_CHANGED_DEF;
+static const char *CTS_NOTI_PLOG_CHANGED="/opt/data/contacts-svc/.CONTACTS_SVC_PLOG_CHANGED";
+static const char *CTS_NOTI_FAVORITE_CHANGED="/opt/data/contacts-svc/.CONTACTS_SVC_FAVOR_CHANGED";
+static const char *CTS_NOTI_SPEEDDIAL_CHANGED="/opt/data/contacts-svc/.CONTACTS_SVC_SPEED_CHANGED";
+static const char *CTS_NOTI_ADDRBOOK_CHANGED="/opt/data/contacts-svc/.CONTACTS_SVC_AB_CHANGED";
+static const char *CTS_NOTI_GROUP_CHANGED="/opt/data/contacts-svc/.CONTACTS_SVC_GROUP_CHANGED";
+static const char *CTS_NOTI_GROUP_RELATION_CHANGED="/opt/data/contacts-svc/.CONTACTS_SVC_GROUP_REL_CHANGED";
+static const char *CTS_NOTI_MISSED_CALL_CHANGED="/opt/data/contacts-svc/.CONTACTS_SVC_MISSED_CHANGED";
+
+static const char *CTS_VCONF_SORTING_ORDER="db/service/contacts/name_sorting_order";
+static const char *CTS_VCONF_DISPLAY_ORDER=CTS_VCONF_DISPLAY_ORDER_DEF;
+
+static int transaction_count = 0;
+static int transaction_ver = 0;
+static bool version_up=false;
+
+static bool contact_change=false;
+static bool plog_change=false;
+static bool missed_change=false;
+static bool favor_change=false;
+static bool speed_change=false;
+static bool addrbook_change=false;
+static bool group_change=false;
+static bool group_rel_change=false;
+
+static int name_sorting_order = -1;
+static int name_display_order = -1;
+static int default_lang = -1;
+
+static void cts_vconf_callback(keynode_t *key, void *data)
+{
+       //if(!strcmp(vconf_keynode_get_name(key), CTS_VCONF_SORTING_ORDER));
+       if (CTS_ORDER_OF_SORTING == (int)data)
+               name_sorting_order = vconf_keynode_get_int(key);
+       else if (CTS_ORDER_OF_DISPLAY == (int)data)
+               name_display_order = vconf_keynode_get_int(key);
+       else if (CTS_ORDER_OF_DISPLAY + 1 == (int)data)
+               default_lang = vconf_keynode_get_int(key);
+}
+
+int cts_get_default_language(void)
+{
+       if (default_lang < 0) {
+               int ret;
+               ret = vconf_get_int(CTS_VCONF_DEFAULT_LANGUAGE, &default_lang);
+               warn_if(ret < 0, "vconf_get_int() Failed(%d)", ret);
+       }
+       return default_lang;
+}
+
+void cts_set_contact_noti(void)
+{
+       contact_change = true;
+}
+void cts_set_plog_noti(void)
+{
+       plog_change = true;
+}
+void cts_set_missed_call_noti(void)
+{
+       missed_change = true;
+}
+void cts_set_favor_noti(void)
+{
+       favor_change = true;
+}
+void cts_set_speed_noti(void)
+{
+       speed_change = true;
+}
+void cts_set_addrbook_noti(void)
+{
+       addrbook_change = true;
+}
+void cts_set_group_noti(void)
+{
+       group_change = true;
+}
+void cts_set_group_rel_noti(void)
+{
+       group_rel_change = true;
+}
+
+static inline void cts_noti_publish_contact_change(void)
+{
+       int fd = open(CTS_NOTI_CONTACT_CHANGED, O_TRUNC | O_RDWR);
+       if (0 <= fd) {
+               close(fd);
+               contact_change = false;
+       }
+}
+
+static inline void cts_noti_publish_plog_change(void)
+{
+       int fd = open(CTS_NOTI_PLOG_CHANGED, O_TRUNC | O_RDWR);
+       if (0 <= fd) {
+               close(fd);
+               plog_change = false;
+       }
+}
+
+static inline void cts_noti_publish_missed_call_change(void)
+{
+       int fd = open(CTS_NOTI_MISSED_CALL_CHANGED, O_TRUNC | O_RDWR);
+       if (0 <= fd) {
+               close(fd);
+               missed_change = false;
+       }
+}
+
+static inline void cts_noti_publish_favor_change(void)
+{
+       int fd = open(CTS_NOTI_FAVORITE_CHANGED, O_TRUNC | O_RDWR);
+       if (0 <= fd) {
+               close(fd);
+               favor_change = false;
+       }
+}
+
+static inline void cts_noti_publish_speed_change(void)
+{
+       int fd = open(CTS_NOTI_SPEEDDIAL_CHANGED, O_TRUNC | O_RDWR);
+       if (0 <= fd) {
+               close(fd);
+               speed_change = false;
+       }
+}
+
+static inline void cts_noti_publish_addrbook_change(void)
+{
+       int fd = open(CTS_NOTI_ADDRBOOK_CHANGED, O_TRUNC | O_RDWR);
+       if (0 <= fd) {
+               close(fd);
+               addrbook_change = false;
+       }
+}
+
+static inline void cts_noti_publish_group_change(void)
+{
+       int fd = open(CTS_NOTI_GROUP_CHANGED, O_TRUNC | O_RDWR);
+       if (0 <= fd) {
+               close(fd);
+               group_change = false;
+       }
+}
+
+static inline void cts_noti_publish_group_rel_change(void)
+{
+       int fd = open(CTS_NOTI_GROUP_RELATION_CHANGED, O_TRUNC | O_RDWR);
+       if (0 <= fd) {
+               close(fd);
+               group_rel_change = false;
+       }
+}
+
+#define CTS_COMMIT_TRY_MAX 500000 // For 3second
+API int contacts_svc_begin_trans(void)
+{
+       int ret = -1, progress;
+
+       if (transaction_count <= 0)
+       {
+               ret = cts_query_exec("BEGIN IMMEDIATE TRANSACTION"); //taken 600ms
+               progress = 100000;
+               while (CTS_ERR_DB_LOCK == ret && progress<CTS_COMMIT_TRY_MAX) {
+                       usleep(progress);
+                       ret = cts_query_exec("BEGIN IMMEDIATE TRANSACTION");
+                       progress *= 2;
+               }
+               retvm_if(CTS_SUCCESS != ret, ret, "cts_query_exec() Failed(%d)", ret);
+
+               transaction_count = 0;
+
+               const char *query = "SELECT ver FROM "CTS_TABLE_VERSION;
+               transaction_ver = cts_query_get_first_int_result(query);
+               version_up = false;
+       }
+       transaction_count++;
+       CTS_DBG("transaction_count : %d.", transaction_count);
+
+       return CTS_SUCCESS;
+}
+
+static inline void cts_cancel_changes(void)
+{
+       contact_change = false;
+       plog_change = false;
+       missed_change = false;
+       favor_change = false;
+       speed_change = false;
+       addrbook_change = false;
+       group_change = false;
+       group_rel_change = false;
+}
+
+API int contacts_svc_end_trans(bool is_success)
+{
+       int ret = -1, progress;
+       char query[CTS_SQL_MIN_LEN];
+
+       transaction_count--;
+
+       if (0 != transaction_count) {
+               CTS_DBG("contact transaction_count : %d.", transaction_count);
+               return CTS_SUCCESS;
+       }
+
+       if (false == is_success) {
+               cts_cancel_changes();
+               ret = cts_query_exec("ROLLBACK TRANSACTION");
+               return CTS_SUCCESS;
+       }
+
+       if (version_up) {
+               transaction_ver++;
+               snprintf(query, sizeof(query), "UPDATE %s SET ver = %d",
+                               CTS_TABLE_VERSION, transaction_ver);
+               ret = cts_query_exec(query);
+               warn_if(CTS_SUCCESS != ret, "cts_query_exec(version up) Failed(%d)", ret);
+       }
+
+       progress = 400000;
+       ret = cts_query_exec("COMMIT TRANSACTION");
+       while (CTS_ERR_DB_LOCK == ret && progress<CTS_COMMIT_TRY_MAX) {
+               usleep(progress);
+               ret = cts_query_exec("COMMIT TRANSACTION");
+               progress *= 2;
+       }
+       if (CTS_SUCCESS != ret) {
+               int tmp_ret;
+               ERR("cts_query_exec() Failed(%d)", ret);
+               cts_cancel_changes();
+               tmp_ret = cts_query_exec("ROLLBACK TRANSACTION");
+               warn_if(CTS_SUCCESS != tmp_ret, "cts_query_exec(ROLLBACK) Failed(%d)", tmp_ret);
+               return ret;
+       }
+       if (contact_change) cts_noti_publish_contact_change();
+       if (plog_change) cts_noti_publish_plog_change();
+       if (missed_change) cts_noti_publish_missed_call_change();
+       if (favor_change) cts_noti_publish_favor_change();
+       if (speed_change) cts_noti_publish_speed_change();
+       if (addrbook_change) cts_noti_publish_addrbook_change();
+       if (group_change) cts_noti_publish_group_change();
+       if (group_rel_change) cts_noti_publish_group_rel_change();
+
+       return transaction_ver;
+}
+
+int cts_get_next_ver(void)
+{
+       const char *query;
+
+       if (0 < transaction_count) {
+               version_up = true;
+               return transaction_ver + 1;
+       }
+
+       query = "SELECT ver FROM "CTS_TABLE_VERSION;
+       return (1+cts_query_get_first_int_result(query));
+}
+
+void cts_deregister_noti(void)
+{
+       int ret;
+
+       cts_inotify_close();
+
+       ret = vconf_ignore_key_changed(CTS_VCONF_SORTING_ORDER, cts_vconf_callback);
+       retm_if(ret<0,"vconf_ignore_key_changed(%s) Failed(%d)",CTS_VCONF_SORTING_ORDER,ret);
+       ret = vconf_ignore_key_changed(CTS_VCONF_DISPLAY_ORDER, cts_vconf_callback);
+       retm_if(ret<0,"vconf_ignore_key_changed(%s) Failed(%d)",CTS_VCONF_DISPLAY_ORDER,ret);
+       ret = vconf_ignore_key_changed(CTS_VCONF_DEFAULT_LANGUAGE, cts_vconf_callback);
+       retm_if(ret<0,"vconf_ignore_key_changed(%s) Failed(%d)",CTS_VCONF_DEFAULT_LANGUAGE,ret);
+}
+
+static inline int cts_conf_init_name_info(void)
+{
+       int ret;
+
+       ret = vconf_get_int(CTS_VCONF_SORTING_ORDER, &name_sorting_order);
+       if (ret < 0) {
+               ERR("vconf_get_int() Failed(%d)", ret);
+               name_sorting_order = CTS_ORDER_NAME_FIRSTLAST;
+       }
+
+       ret = vconf_get_int(CTS_VCONF_DISPLAY_ORDER, &name_display_order);
+       if (ret < 0) {
+               ERR("vconf_get_int() Failed(%d)", ret);
+               name_display_order = CTS_ORDER_NAME_FIRSTLAST;
+       }
+
+       ret = vconf_get_int(CTS_VCONF_DEFAULT_LANGUAGE, &default_lang);
+       warn_if(ret < 0, "vconf_get_int() Failed(%d)", ret);
+
+       ret = vconf_notify_key_changed(CTS_VCONF_SORTING_ORDER,
+                       cts_vconf_callback, (void *)CTS_ORDER_OF_SORTING);
+       retvm_if(ret<0, CTS_ERR_VCONF_FAILED, "vconf_notify_key_changed() Failed(%d)", ret);
+       ret = vconf_notify_key_changed(CTS_VCONF_DISPLAY_ORDER,
+                       cts_vconf_callback, (void *)CTS_ORDER_OF_DISPLAY);
+       retvm_if(ret<0, CTS_ERR_VCONF_FAILED, "vconf_notify_key_changed() Failed(%d)", ret);
+       ret = vconf_notify_key_changed(CTS_VCONF_DEFAULT_LANGUAGE,
+                       cts_vconf_callback, (void *)CTS_ORDER_OF_DISPLAY+1);
+       retvm_if(ret<0, CTS_ERR_VCONF_FAILED, "vconf_notify_key_changed() Failed(%d)", ret);
+
+       return CTS_SUCCESS;
+}
+
+void cts_register_noti(void)
+{
+       int ret;
+
+       ret = cts_inotify_init();
+       retm_if(CTS_SUCCESS != ret, "cts_inotify_init() Failed(%d)", ret);
+
+       ret = cts_conf_init_name_info();
+       retm_if(CTS_SUCCESS != ret, "cts_conf_init_name_info() Failed(%d)", ret);
+}
+
+API int contacts_svc_set_order(cts_order_op op_code, cts_order_type order)
+{
+       int ret;
+       const char *op;
+
+       retvm_if(CTS_ORDER_NAME_FIRSTLAST != order && CTS_ORDER_NAME_LASTFIRST != order,
+                       CTS_ERR_ARG_INVALID, "The parameter(order:%d) is Invalid", order);
+
+       if (CTS_ORDER_OF_SORTING == op_code)
+               op = CTS_VCONF_SORTING_ORDER;
+       else
+               op = CTS_VCONF_DISPLAY_ORDER;
+
+       ret = vconf_set_int(op, order);
+       retvm_if(ret<0, CTS_ERR_VCONF_FAILED, "vconf_set_int(%s) Failed(%d)", op, ret);
+
+       if (CTS_ORDER_OF_SORTING == op_code)
+               name_sorting_order = order;
+       else
+               name_display_order = order;
+
+       return CTS_SUCCESS;
+}
+
+API cts_order_type contacts_svc_get_order(cts_order_op op_code)
+{
+       int ret;
+
+       if (CTS_ORDER_OF_SORTING == op_code) {
+               if (name_sorting_order < 0) {
+                       ret = vconf_get_int(CTS_VCONF_SORTING_ORDER, &name_sorting_order);
+                       retvm_if(ret<0, CTS_ERR_VCONF_FAILED, "vconf_get_int() Failed(%d)", ret);
+               }
+
+               return name_sorting_order;
+       }
+       else{
+               if (name_display_order < 0) {
+                       ret = vconf_get_int(CTS_VCONF_DISPLAY_ORDER, &name_display_order);
+                       retvm_if(ret<0, CTS_ERR_VCONF_FAILED, "vconf_get_int() Failed(%d)", ret);
+               }
+
+               return name_display_order;
+       }
+}
+
+static inline const char* cts_noti_get_file_path(int type)
+{
+       const char *noti;
+       switch (type)
+       {
+       case CTS_SUBSCRIBE_CONTACT_CHANGE:
+               noti = CTS_NOTI_CONTACT_CHANGED;
+               break;
+       case CTS_SUBSCRIBE_PLOG_CHANGE:
+               noti = CTS_NOTI_PLOG_CHANGED;
+               break;
+       case CTS_SUBSCRIBE_MISSED_CALL_CHANGE:
+               noti = CTS_NOTI_MISSED_CALL_CHANGED;
+               break;
+       case CTS_SUBSCRIBE_FAVORITE_CHANGE:
+               noti = CTS_NOTI_FAVORITE_CHANGED;
+               break;
+       case CTS_SUBSCRIBE_GROUP_CHANGE:
+               noti = CTS_NOTI_GROUP_CHANGED;
+               break;
+       case CTS_SUBSCRIBE_SPEEDDIAL_CHANGE:
+               noti = CTS_NOTI_SPEEDDIAL_CHANGED;
+               break;
+       case CTS_SUBSCRIBE_ADDRESSBOOK_CHANGE:
+               noti = CTS_NOTI_ADDRBOOK_CHANGED;
+               break;
+       default:
+               ERR("Invalid parameter : The type(%d) is not supported", type);
+               return NULL;
+       }
+
+       return noti;
+}
+
+API int contacts_svc_subscribe_change(cts_subscribe_type noti_type,
+               void (*cb)(void *), void *user_data)
+{
+       int ret;
+       const char *noti;
+
+       noti = cts_noti_get_file_path(noti_type);
+       retvm_if(NULL == noti, CTS_ERR_ARG_INVALID,
+                       "cts_noti_get_file_path(%d) Failed", noti_type);
+
+       ret = cts_inotify_subscribe(noti, cb, user_data);
+       retvm_if(CTS_SUCCESS != ret, ret,
+                       "cts_inotify_subscribe(%d) Failed(%d)", noti_type, ret);
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_unsubscribe_change(cts_subscribe_type noti_type,
+               void (*cb)(void *))
+{
+       int ret;
+       const char *noti;
+
+       noti = cts_noti_get_file_path(noti_type);
+       retvm_if(NULL == noti, CTS_ERR_ARG_INVALID,
+                       "cts_noti_get_file_path(%d) Failed", noti_type);
+
+       ret = cts_inotify_unsubscribe(noti, cb);
+       retvm_if(CTS_SUCCESS != ret, ret,
+                       "cts_inotify_unsubscribe(%d) Failed(%d)", noti_type, ret);
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_unsubscribe_change_with_data(cts_subscribe_type noti_type,
+               void (*cb)(void *), void *user_data)
+{
+       int ret;
+       const char *noti;
+
+       noti = cts_noti_get_file_path(noti_type);
+       retvm_if(NULL == noti, CTS_ERR_ARG_INVALID,
+                       "cts_noti_get_file_path(%d) Failed", noti_type);
+
+       ret = cts_inotify_unsubscribe_with_data(noti, cb, user_data);
+       retvm_if(CTS_SUCCESS != ret, ret,
+                       "cts_inotify_unsubscribe_with_data(%d) Failed(%d)", noti_type, ret);
+
+       return CTS_SUCCESS;
+}
+
+int cts_exist_file(char *path)
+{
+       int fd = open(path, O_RDONLY);
+       // errno == ENOENT
+       retvm_if(fd < 0, CTS_ERR_FAIL, "Open(%s) Failed(%d)", path, errno);
+       close(fd);
+       return CTS_SUCCESS;
+}
+
+#define CTS_COPY_SIZE_MAX 4096
+API int contacts_svc_get_image(cts_img_t img_type, int index, char **img_path)
+{
+       int ret;
+       cts_stmt stmt;
+       char *tmp_path;
+       char query[CTS_SQL_MIN_LEN] = {0};
+
+       retvm_if(CTS_IMG_FULL != img_type && CTS_IMG_NORMAL != img_type,
+                       CTS_ERR_ARG_INVALID,
+                       "You have to use CTS_IMG_FULL or CTS_IMG_NORMAL for img_type");
+       retvm_if(NULL == img_path, CTS_ERR_ARG_INVALID, "img_path is NULL");
+
+       snprintf(query, sizeof(query),
+                               "SELECT image%d FROM %s WHERE contact_id = %d",
+                               img_type, CTS_TABLE_CONTACTS, index);
+
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       *img_path = NULL;
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret) {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_DB_RECORD_NOT_FOUND;
+       }
+
+       tmp_path = cts_stmt_get_text(stmt, 0);
+       if (tmp_path) {
+               ret = cts_exist_file(tmp_path);
+               retvm_if(ret, ret, "cts_exist_file() Failed(%d)", ret);
+               *img_path = strdup(tmp_path);
+               if (NULL == *img_path) {
+                       ERR("strdup() Failed");
+                       cts_stmt_finalize(stmt);
+                       return CTS_ERR_OUT_OF_MEMORY;
+               }
+       }
+       cts_stmt_finalize(stmt);
+       return CTS_SUCCESS;
+}
+
+int cts_delete_image_file(int img_type, int index)
+{
+       int ret;
+       cts_stmt stmt;
+       char *tmp_path;
+       char query[CTS_SQL_MIN_LEN];
+       snprintf(query, sizeof(query),
+                       "SELECT image%d FROM %s WHERE contact_id = %d",
+                       img_type, CTS_TABLE_CONTACTS, index);
+
+       stmt = cts_query_prepare(query);
+       if (NULL == stmt) {
+               ERR("cts_query_prepare() Failed");
+               return CTS_ERR_DB_FAILED;
+       }
+
+       ret = cts_stmt_step(stmt);
+       if (CTS_TRUE != ret) {
+               ERR("cts_stmt_step() Failed(%d)", ret);
+               cts_stmt_finalize(stmt);
+               return CTS_ERR_DB_RECORD_NOT_FOUND;
+       }
+
+       tmp_path = cts_stmt_get_text(stmt, 0);
+       if (tmp_path) {
+               ret = unlink(tmp_path);
+               warn_if (ret < 0, "unlink(%s) Failed(%d)", tmp_path, errno);
+       }
+       cts_stmt_finalize(stmt);
+       return CTS_SUCCESS;
+}
+
+int cts_add_image_file(int img_type, int index, char *src_img, char **dest_img)
+{
+       int src_fd;
+       int dest_fd;
+       int size;
+       int ret;
+       char *ext;
+       char buf[CTS_COPY_SIZE_MAX];
+       char dest[CTS_IMG_PATH_SIZE_MAX];
+
+       *dest_img = NULL;
+       retvm_if(NULL == src_img, CTS_ERR_ARG_INVALID, "img_path is NULL");
+
+       ext = strrchr(src_img, '.');
+       if (NULL == ext) ext = "";
+
+       size = snprintf(dest, sizeof(dest), "%s/%d-%d%s",
+                       CTS_IMAGE_LOCATION, index, img_type, ext);
+       retvm_if(size<=0, CTS_ERR_FAIL, "Destination file name was not created");
+
+       src_fd = open(src_img, O_RDONLY);
+       retvm_if(src_fd < 0, CTS_ERR_IO_ERR, "Open(%s) Failed(%d)", src_img, errno);
+       dest_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, 0660);
+       if (dest_fd < 0) {
+               ERR("Open(%s) Failed(%d)", dest, errno);
+               close(src_fd);
+               return CTS_ERR_FAIL;
+       }
+
+       while ((size = read(src_fd, buf, CTS_COPY_SIZE_MAX)) > 0) {
+               ret = write(dest_fd, buf, size);
+               if (ret <= 0) {
+                       if (EINTR == errno)
+                               continue;
+                       else {
+                               ERR("write() Failed(%d)", errno);
+                               if (ENOSPC == errno)
+                                       ret = CTS_ERR_NO_SPACE;
+                               else
+                                       ret = CTS_ERR_IO_ERR;
+                               close(src_fd);
+                               close(dest_fd);
+                               unlink(dest);
+                               return ret;
+                       }
+               }
+       }
+
+       fchown(dest_fd, getuid(), CTS_SECURITY_FILE_GROUP);
+       fchmod(dest_fd, CTS_SECURITY_DEFAULT_PERMISSION);
+       close(src_fd);
+       close(dest_fd);
+       *dest_img = strdup(dest);
+       return CTS_SUCCESS;
+}
+
+int cts_update_image_file(int img_type, int index, char *src_img, char **dest_img)
+{
+       int ret;
+
+       *dest_img = NULL;
+       ret = cts_delete_image_file(img_type, index);
+       retvm_if(CTS_SUCCESS != ret && CTS_ERR_DB_RECORD_NOT_FOUND != ret,
+               ret, "cts_delete_image_file() Failed(%d)", ret);
+
+       if (src_img) {
+               ret = cts_add_image_file(img_type, index, src_img, &(*dest_img));
+               retvm_if(CTS_SUCCESS != ret, ret, "cts_add_image_file() Failed(%d)", ret);
+       }
+
+       return ret;
+}
+
+int cts_update_contact_changed_time(int contact_id)
+{
+       int ret;
+       char query[CTS_SQL_MIN_LEN];
+
+       snprintf(query, sizeof(query),
+                       "UPDATE %s SET changed_ver=%d, changed_time=%d WHERE contact_id=%d",
+                       CTS_TABLE_CONTACTS, cts_get_next_ver(), (int)time(NULL), contact_id);
+
+       ret = cts_query_exec(query);
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_query_exec() Failed(%d)", ret);
+
+       cts_set_contact_noti();
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_save_image(cts_img_t img_type, int index, char *src_img)
+{
+       int ret;
+       char *dest_img;
+       char query[CTS_SQL_MIN_LEN];
+       cts_stmt stmt;
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       ret = cts_update_image_file(img_type, index, src_img, &dest_img);
+       if (CTS_SUCCESS != ret) {
+               ERR("cts_update_image_file() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       snprintf(query, sizeof(query),
+                       "UPDATE %s SET changed_ver=%d, changed_time=%d, image%d=? WHERE contact_id=%d",
+                       CTS_TABLE_CONTACTS, cts_get_next_ver(), (int)time(NULL), img_type, index);
+       stmt = cts_query_prepare(query);
+       if (NULL == stmt) {
+               ERR("cts_query_prepare() Failed");
+               contacts_svc_end_trans(false);
+               return CTS_ERR_DB_FAILED;
+       }
+
+       if(dest_img)
+               cts_stmt_bind_text(stmt, 1, dest_img);
+       ret = cts_stmt_step(stmt);
+       warn_if(CTS_SUCCESS != ret, "cts_stmt_step() Failed(%d)", ret);
+       cts_stmt_finalize(stmt);
+
+       cts_set_contact_noti();
+
+       ret = contacts_svc_end_trans(true);
+       retvm_if(ret < CTS_SUCCESS, ret, "contacts_svc_end_trans() Failed(%d)", ret);
+
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_count_with_int(cts_count_int_op op_code, int search_value)
+{
+       int ret;
+       cts_stmt stmt;
+       char query[CTS_SQL_MIN_LEN] = {0};
+
+       switch (op_code)
+       {
+       case CTS_GET_COUNT_CONTACTS_IN_ADDRESSBOOK:
+               snprintf(query, sizeof(query),
+                               "SELECT COUNT(contact_id) FROM %s "
+                               "WHERE addrbook_id = ?", CTS_TABLE_CONTACTS);
+               break;
+       case CTS_GET_COUNT_CONTACTS_IN_GROUP:
+               snprintf(query, sizeof(query),
+                               "SELECT COUNT(contact_id) FROM %s WHERE group_id = ?",
+                               CTS_TABLE_GROUPING_INFO);
+               break;
+       case CTS_GET_COUNT_NO_GROUP_CONTACTS_IN_ADDRESSBOOK:
+               snprintf(query, sizeof(query),
+                               "SELECT COUNT(contact_id) FROM %s A "
+                               "WHERE addrbook_id = ? AND NOT EXISTS "
+                               "(SELECT contact_id FROM %s WHERE contact_id=A.contact_id LIMIT 1)",
+                               CTS_TABLE_CONTACTS, CTS_TABLE_GROUPING_INFO);
+               break;
+       default:
+               ERR("Invalid parameter : The op_code(%d) is not supported", op_code);
+               return CTS_ERR_ARG_INVALID;
+       }
+       stmt = cts_query_prepare(query);
+       retvm_if(NULL == stmt, CTS_ERR_DB_FAILED, "cts_query_prepare() Failed");
+
+       cts_stmt_bind_int(stmt, 1, search_value);
+       ret = cts_stmt_get_first_int_result(stmt);
+       if (CTS_ERR_DB_RECORD_NOT_FOUND == ret) return 0;
+       else return ret;
+}
+
+API int contacts_svc_count(cts_count_op op_code)
+{
+       int ret;
+       char query[CTS_SQL_MIN_LEN] = {0};
+
+       switch ((int)op_code)
+       {
+       case CTS_GET_ALL_CONTACT:
+               snprintf(query, sizeof(query),"SELECT COUNT(*) FROM %s",
+                               CTS_TABLE_CONTACTS);
+               break;
+       case CTS_GET_COUNT_SDN:
+               snprintf(query, sizeof(query),"SELECT COUNT(*) FROM %s",
+                               CTS_TABLE_SIM_SERVICES);
+               break;
+       case CTS_GET_ALL_PHONELOG:
+               snprintf(query, sizeof(query), "SELECT COUNT(*) FROM %s",
+                               CTS_TABLE_PHONELOGS);
+               break;
+       case CTS_GET_UNSEEN_MISSED_CALL:
+               snprintf(query, sizeof(query),
+                               "SELECT COUNT(*) FROM %s "
+                               "WHERE log_type = %d OR log_type = %d",
+                               CTS_TABLE_PHONELOGS,
+                               CTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN, CTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN);
+               break;
+       default:
+               ERR("Invalid parameter : The op_code(%d) is not supported", op_code);
+               return CTS_ERR_ARG_INVALID;
+       }
+
+       ret = cts_query_get_first_int_result(query);
+       if (CTS_ERR_DB_RECORD_NOT_FOUND == ret) return 0;
+       else return ret;
+}
+
+int cts_convert_nicknames2textlist(GSList *src, char *dest, int dest_size)
+{
+       int len;
+       GSList *nick_repeat = src;
+       cts_nickname *nick_data;
+
+       retvm_if(dest_size <= 0 || NULL == dest, CTS_ERR_ARG_INVALID,
+                       "The parameter is Invalid. dest = %p, dest_size = %d", dest, dest_size);
+
+       len = 0;
+       dest[0] = '\0';
+       while (nick_repeat) {
+               if (NULL != (nick_data = (cts_nickname *)nick_repeat->data) && nick_data->nick) {
+                       if (!nick_data->deleted)
+                               len += snprintf(dest+len, dest_size-len, "%s,", nick_data->nick);
+               }
+               nick_repeat = nick_repeat->next;
+       }
+
+       len = strlen(dest);
+       if (len)
+               dest[len - 1] = '\0';
+       else
+               return CTS_ERR_NO_DATA;
+       return CTS_SUCCESS;
+}
+
+GSList* cts_convert_textlist2nicknames(char *text_list)
+{
+       char temp[CTS_SQL_MAX_LEN], *text_start, *text_end;
+       GSList *ret_list = NULL;
+       cts_nickname *result;
+
+       snprintf(temp, sizeof(temp), "%s", text_list);
+
+       text_start = temp;
+       while (text_start)
+       {
+               text_end = strchr(text_start, ',');
+               if (text_end)
+                       *text_end = '\0';
+
+               result = (cts_nickname *)contacts_svc_value_new(CTS_VALUE_NICKNAME);
+               if (result)
+               {
+                       result->embedded = true;
+                       result->nick = strdup(text_start);
+               }
+
+               ret_list = g_slist_append(ret_list, result);
+
+               if (text_end) {
+                       *text_end = ',';
+                       text_start = text_end+1;
+               }
+               else
+                       text_start = NULL;
+       }
+       return ret_list;
+}
+
+API int contacts_svc_import_sim(void)
+{
+       int ret;
+
+       cts_mutex_lock(CTS_MUTEX_SOCKET_FD);
+       ret = cts_request_sim_import();
+       cts_mutex_unlock(CTS_MUTEX_SOCKET_FD);
+
+       return ret;
+}
+
+int cts_increase_outgoing_count(int contact_id)
+{
+       int ret;
+       char query[CTS_SQL_MIN_LEN];
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       snprintf(query, sizeof(query),
+                       "UPDATE %s SET outgoing_count = outgoing_count + 1 WHERE contact_id = %d",
+                       CTS_TABLE_CONTACTS, contact_id);
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+API int contacts_svc_reset_outgoing_count(int contact_id)
+{
+       int ret ;
+       char query[CTS_SQL_MAX_LEN];
+
+       snprintf(query, sizeof(query),
+                       "UPDATE %s SET outgoing_count = 0 WHERE contact_id = %d",
+                       CTS_TABLE_CONTACTS, contact_id);
+
+       ret = contacts_svc_begin_trans();
+       retvm_if(ret, ret, "contacts_svc_begin_trans() Failed(%d)", ret);
+
+       ret = cts_query_exec(query);
+       if (CTS_SUCCESS != ret)
+       {
+               ERR("cts_query_exec() Failed(%d)", ret);
+               contacts_svc_end_trans(false);
+               return ret;
+       }
+
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS)
+               return ret;
+       else
+               return CTS_SUCCESS;
+}
+
+#ifdef CTS_TIMECHECK
+double cts_set_start_time(void)
+{
+       struct timeval tv;
+       double curtime;
+
+       gettimeofday(&tv, NULL);
+       curtime = tv.tv_sec * 1000 + (double)tv.tv_usec/1000;
+       return curtime;
+}
+
+double cts_exec_time(double start)
+{
+       double end = cts_set_start_time();
+       return (end - start - correction);
+}
+
+int cts_init_time(void)
+{
+       double temp_t;
+       temp_t = cts_set_start_time();
+       correction = cts_exec_time(temp_t);
+
+       return 0;
+}
+#endif
+
diff --git a/src/cts-utils.h b/src/cts-utils.h
new file mode 100755 (executable)
index 0000000..6350fc8
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_UTILS_H__
+#define __CTS_UTILS_H__
+
+#include <stdbool.h>
+
+#define CTS_IMG_PATH_SIZE_MAX 1024
+#define CTS_IMAGE_LOCATION "/opt/data/contacts-svc/img"
+#define CTS_VCARD_IMAGE_LOCATION "/opt/data/contacts-svc/img/vcard"
+#define CTS_NOTI_CONTACT_CHANGED_DEF "/opt/data/contacts-svc/.CONTACTS_SVC_DB_CHANGED"
+#define CTS_VCONF_DISPLAY_ORDER_DEF "db/service/contacts/name_display_order"
+
+void cts_deregister_noti(void);
+void cts_register_noti(void);
+int cts_get_default_language(void);
+void cts_set_contact_noti(void);
+void cts_set_plog_noti(void);
+void cts_set_missed_call_noti(void);
+void cts_set_favor_noti(void);
+void cts_set_speed_noti(void);
+void cts_set_addrbook_noti(void);
+void cts_set_group_noti(void);
+void cts_set_group_rel_noti(void);
+int cts_exist_file(char *path);
+int cts_convert_nicknames2textlist(GSList *src, char *dest, int dest_size);
+GSList* cts_convert_textlist2nicknames(char *text_list);
+int cts_increase_outgoing_count(int contact_id);
+int cts_get_next_ver(void);
+int cts_update_contact_changed_time(int contact_id);
+int cts_delete_image_file(int img_type, int index);
+int cts_add_image_file(int img_type, int index, char *src_img, char **dest_img);
+int cts_update_image_file(int img_type, int index, char *src_img, char **dest_img);
+
+#ifndef __CONTACTS_SVC_H__
+//<!--
+/**
+ * This function starts database transaction
+ * If you want to handle a transaction, use it.
+ *
+ * @par Multiple inserting case
+ * case1 has only one DB commit. Therefore it is faster than case 2.
+ * And if 5th inserted contact is failed,
+ * case 1 insert nothing but case 2 insert 1,2,3 and 4th contacts.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @code
+ * //case 1
+ * contacts_svc_begin_trans();
+ * for(i = 0; i< 20; i++) {
+ *    if(CTS_SUCCESS != "insert api") {
+ *       contacts_svc_end_trans(false);
+ *       return -1;
+ *    }
+ * }
+ * ret = contacts_svc_end_trans(true);
+ * if(ret < CTS_SUCCESS){
+ *  printf("all work were rollbacked");
+ *   return;
+ * }
+ *
+ * //case 2
+ * for(i = 0; i< 20; i++) {
+ *    if(CTS_SUCCESS != "insert api") {
+ *       return -1;
+ *    }
+ * }
+ * @endcode
+ */
+int contacts_svc_begin_trans(void);
+
+/**
+ * This function finishes database transaction of contacts service
+ * If you want to handle a transaction, use it.
+ * If returned value is error, the transaction was rollbacked.
+ * When transaction is success, it returns the last contacts version.
+ *
+ * @param[in] is_success true : commit, false : rollback
+ * @return #CTS_SUCCESS or the last contact version(when success) on success,
+ *         Negative value(#cts_error) on error
+ */
+int contacts_svc_end_trans(bool is_success);
+
+/**
+ * A kind of order in contacts service of contacts service
+ * @see contacts_svc_get_order()
+ */
+typedef enum{
+       CTS_ORDER_NAME_FIRSTLAST, /**<First Name first */
+       CTS_ORDER_NAME_LASTFIRST  /**<Last Name first */
+}cts_order_type;
+
+/**
+ * Use for contacts_svc_get_order().
+ */
+typedef enum{
+       CTS_ORDER_OF_SORTING, /**< Sorting Order */
+       CTS_ORDER_OF_DISPLAY /**< Display Order */
+}cts_order_op;
+
+/**
+ * This function gets the display or sorting order(Firstname first or LastName first)
+ *
+ * @param[in] op_code #cts_order_op
+ * @return #CTS_ORDER_NAME_FIRSTLAST or #CTS_ORDER_NAME_LASTFIRST on success,
+ *           \n Negative value(#cts_error) on error
+ */
+cts_order_type contacts_svc_get_order(cts_order_op op_code);
+
+/**
+ * This function sets the display or sorting order(Firstname first or LastName first)
+ *
+ * @param[in] op_code #cts_order_op
+ * @param[in] order order type(#cts_order_type)
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_set_order(cts_order_op op_code, cts_order_type order);
+
+/**
+ * Use for contacts_svc_subscribe_change(), contacts_svc_unsubscribe_change()
+ */
+typedef enum{
+       CTS_SUBSCRIBE_CONTACT_CHANGE,
+       CTS_SUBSCRIBE_PLOG_CHANGE,
+       CTS_SUBSCRIBE_FAVORITE_CHANGE,
+       CTS_SUBSCRIBE_GROUP_CHANGE,
+       CTS_SUBSCRIBE_SPEEDDIAL_CHANGE,
+       CTS_SUBSCRIBE_ADDRESSBOOK_CHANGE,
+       CTS_SUBSCRIBE_MISSED_CALL_CHANGE
+}cts_subscribe_type;
+
+/**
+ * This function watchs contacts service changes.
+ * The notification is sent once per a transaction.
+ * This is handled by default context of g_main_loop.
+ *
+ * @param[in] noti_type A kind of Notification
+ * @param[in] cb callback function pointer
+ * @param[in] user_data data which is passed to callback function
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @par example
+ * @code
+#include <stdio.h>
+#include <glib.h>
+#include <contacts-svc.h>
+
+void test_callback(void *data)
+{
+   printf("Contact data of contacts service is changed\n");
+}
+
+int main()
+{
+   GMainLoop *loop;
+
+   contacts_svc_subscribe_change(CTS_SUBSCRIBE_CONTACT_CHANGE, test_callback, NULL);
+
+   loop = g_main_loop_new(NULL, FALSE);
+   g_main_loop_run(loop);
+
+   contacts_svc_unsubscribe_change(CTS_SUBSCRIBE_CONTACT_CHANGE, test_callback);
+   g_main_loop_unref(loop);
+
+   return 0;
+}
+ * @endcode
+ */
+int contacts_svc_subscribe_change(cts_subscribe_type noti_type,
+               void (*cb)(void *), void *user_data);
+
+/**
+ * This function stops to watch contacts service changes.
+ * @param[in] noti_type A kind of Notification(#cts_subscribe_type)
+ * @param[in] cb callback function which is added by contacts_svc_subscribe_change()
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_unsubscribe_change(cts_subscribe_type noti_type,
+               void (*cb)(void *));
+
+/**
+ * This function delete a callback function which is specified with user_data.
+ * @param[in] noti_type A kind of Notification(#cts_subscribe_type)
+ * @param[in] cb The callback function which is added by contacts_svc_subscribe_change()
+ * @param[in] user_data The user_data which is added by contacts_svc_subscribe_change()
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_unsubscribe_change_with_data(cts_subscribe_type noti_type,
+               void (*cb)(void *), void *user_data);
+
+/**
+ * Use for contacts_svc_count()
+ */
+typedef enum
+{
+       CTS_GET_ALL_CONTACT, /**< The count of contacts in the all addressbook */
+       CTS_GET_COUNT_SDN, /**< The count of SDN(Service Dialing Number) in SIM */
+       CTS_GET_ALL_PHONELOG, /**< The count of all phonelog */
+       CTS_GET_UNSEEN_MISSED_CALL, /**< The count of unseen missed call */
+}cts_count_op;
+/**
+ * This function gets count related with op_code.
+ *
+ * @param[in] op_code #cts_count_op
+ * @return The count number on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_count(cts_count_op op_code);
+
+/**
+ * Use for contacts_svc_count_with_int()
+ */
+typedef enum
+{
+       CTS_GET_COUNT_CONTACTS_IN_ADDRESSBOOK, /**< The count of contacts in the addressbook related to index(search_value) */
+       CTS_GET_COUNT_CONTACTS_IN_GROUP, /**< The count of contacts in the group related to index(search_value) */
+       CTS_GET_COUNT_NO_GROUP_CONTACTS_IN_ADDRESSBOOK, /**< The count of not assigned contacts in the addressbook related to index(search_value) */
+}cts_count_int_op;
+/**
+ * This function gets count related with op_code and search_value.
+ * \n #search_value is related with op_code. The Word after preposition is a property of search_value.
+ *
+ * @param[in] op_code #cts_count_int_op
+ * @param[in] search_value interger value(almost a related index) for searching
+ * @return The count number on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_count_with_int(cts_count_int_op op_code, int search_value);
+
+/**
+ * Use for contacts_svc_save_image()
+ */
+typedef enum
+{
+       CTS_IMG_NORMAL, /**< . */
+       CTS_IMG_FULL, /**< . */
+} cts_img_t;
+
+/**
+ * This function saves image to contacts service domain.
+ *
+ * @param[in] img_type #cts_img_t
+ * @param[in] index index of contact
+ * @param[in] src_img The image path to copy(Should include extension at path)
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_save_image(cts_img_t img_type, int index, char *src_img);
+
+/**
+ * This function gets image from contacts service domain.
+ * Usually, You can get the #CTS_IMG_NORMAL in Contacts Struct(#CTSstruct).
+ *
+ * @param[in] img_type #cts_img_t
+ * @param[in] index index of contact
+ * @param[in] img_path The pointer of getting image path(should be freed by using free())
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_get_image(cts_img_t img_type, int index, char **img_path);
+
+/**
+ * This function imports sim phonebook.
+ *
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_import_sim(void);
+
+/**
+ * This function sets the outgoing count of the contact to zero.
+ *
+ * @param[in] contact_id The index of contact
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ * @see contacts_svc_get_list(), #CTS_LIST_OFTEN_USED_CONTACT
+ */
+int contacts_svc_reset_outgoing_count(int contact_id);
+
+//-->
+#endif //#ifndef __CONTACTS_SVC_H__
+
+#endif //__CTS_UTILS_H__
+
diff --git a/src/cts-vcard-file.c b/src/cts-vcard-file.c
new file mode 100755 (executable)
index 0000000..cf8e6ce
--- /dev/null
@@ -0,0 +1,1765 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <iconv.h>
+
+#include "cts-internal.h"
+#include "cts-types.h"
+#include "cts-utils.h"
+#include "cts-normalize.h"
+#include "cts-vcard.h"
+#include "cts-vcard-file.h"
+
+static int cts_tmp_photo_id;
+
+enum {
+       CTS_VCARD_VER_NONE,
+       CTS_VCARD_VER_2_1,
+       CTS_VCARD_VER_3_0,
+       CTS_VCARD_VER_4_0,
+};
+
+enum {
+       CTS_VCARD_VALUE_NONE,
+       CTS_VCARD_VALUE_FN,
+       CTS_VCARD_VALUE_N,
+       CTS_VCARD_VALUE_NICKNAME,
+       CTS_VCARD_VALUE_PHOTO,
+       CTS_VCARD_VALUE_BDAY,
+       CTS_VCARD_VALUE_ADR,
+       CTS_VCARD_VALUE_LABEL,
+       CTS_VCARD_VALUE_TEL,
+       CTS_VCARD_VALUE_EMAIL,
+       CTS_VCARD_VALUE_TITLE,
+       CTS_VCARD_VALUE_ROLE,
+       CTS_VCARD_VALUE_ORG,
+       CTS_VCARD_VALUE_NOTE,
+       CTS_VCARD_VALUE_REV,
+       CTS_VCARD_VALUE_UID,
+       CTS_VCARD_VALUE_URL,
+       CTS_VCARD_VALUE_X_ANNIVERSARY,
+       CTS_VCARD_VALUE_X_IRMC_LUID,
+       CTS_VCARD_VALUE_X_SLP_GROUP,
+       CTS_VCARD_VALUE_END,
+       CTS_VCARD_VALUE_MAX
+};
+
+static const char *content_name[CTS_VCARD_VALUE_MAX];
+
+static inline char* cts_vcard_remove_empty_line(char *src)
+{
+       while (*src) {
+               if ('\n' != *src && '\r' != *src)
+                       break;
+               src++;
+       }
+       return src;
+}
+
+static char* cts_vcard_check_word(char *src, const char *word)
+{
+       bool start = false;
+
+       retvm_if(NULL == src, NULL, "The src is NULL.");
+
+       src = cts_vcard_remove_empty_line(src);
+
+       while (*src) {
+               switch (*src) {
+               case ' ':
+               case ':':
+               case ';':
+                       src++;
+                       break;
+               default:
+                       start = true;
+                       break;
+               }
+               if (start) break;
+       }
+
+       while (*src == *word) {
+               src++;
+               word++;
+
+               if ('\0' == *src || '\0' == *word)
+                       break;
+       }
+
+       if ('\0' == *word)
+               return src;
+       else
+               return NULL;
+}
+
+static int cts_vcard_check_content_type(char **vcard)
+{
+       int i;
+       char *new_start;
+
+       for (i=CTS_VCARD_VALUE_NONE+1;i<CTS_VCARD_VALUE_MAX;i++) {
+               new_start = cts_vcard_check_word(*vcard, content_name[i]);
+               if (new_start && (':' == *new_start || ';' == *new_start))
+                       break;
+       }
+
+       if (CTS_VCARD_VALUE_MAX == i)
+               return CTS_VCARD_VALUE_NONE;
+       else {
+               *vcard = new_start;
+               return i;
+       }
+}
+
+static inline int cts_vcard_check_quoted(char *src)
+{
+       int ret;
+
+       while (*src) {
+               if ('Q' == *src) {
+                       ret = strncmp(src, "QUOTED-PRINTABLE", sizeof("QUOTED-PRINTABLE") - 1);
+                       if (!ret)
+                               return CTS_TRUE;
+               }else if (':' == *src) {
+                       break;
+               }
+               src++;
+       }
+       return CTS_FALSE;
+}
+
+static inline int cts_vcard_hex_to_dec(char hex)
+{
+       switch (hex) {
+       case '0' ... '9':
+               return hex - '0';
+       case 'a' ... 'f':
+               return hex - 'a' + 10;
+       case 'A' ... 'F':
+               return hex - 'A' + 10;
+       default:
+               return 0;
+       }
+}
+static inline int cts_vcard_decode_quoted_val(char *val)
+{
+       char *src, *dest;
+
+       src = strchr(val, ':');
+       if (NULL == src)
+               src = val;
+
+       dest = src;
+       while (*src) {
+               if ('=' == *src) {
+                       *dest = (char)((cts_vcard_hex_to_dec(*(src+1)) << 4) + cts_vcard_hex_to_dec(*(src+2)));
+                       if (*(src+1) && *(src+2))
+                               src += 2;
+               }else
+                       *dest = *src;
+               dest++;
+               src++;
+       }
+
+       *dest = '\0';
+       return dest - val;
+}
+
+static inline char* cts_vcard_translate_charset(char *src, int len)
+{
+       int ret;
+       char *val = src;
+
+       while (*val) {
+               if ('C' == *val) {
+                       ret = strncmp(val, "CHARSET", sizeof("CHARSET") - 1);
+                       if (!ret) {
+                               val += sizeof("CHARSET");
+                               break;
+                       }
+               }else if (':' == *val) {
+                       return NULL;
+               }
+               val++;
+       }
+
+       if (*val) {
+               int src_len, dest_len, i = 0;
+               iconv_t ic;
+               char enc[32], *dest;
+
+               while (';' != *val && ':' != *val) {
+                       enc[i++] = *val++;
+               }
+               enc[i] = '\0';
+               if (0 == strcasecmp("UTF-8", enc))
+                       return NULL;
+
+               while (':' != *val)
+                       val++;
+
+               ic = iconv_open("UTF-8", enc);
+               retvm_if(ic == (iconv_t)-1, NULL, "iconv_open(%s) Failed", enc);
+
+               src_len = len - (val - src);
+               dest_len = 2048;
+               dest = malloc(dest_len);
+
+               while (true) {
+                       char *in = val;
+                       char *out = dest;
+                       size_t in_byte = src_len;
+                       size_t out_byte = dest_len;
+
+                       ret = iconv(ic, &in, &in_byte, &out, &out_byte);
+
+                       if (-1 == ret) {
+                               if (E2BIG == errno) {
+                                       dest_len *= 2;
+                                       dest = realloc(dest, dest_len);
+                                       continue;
+                               } else {
+                                       if (dest) {
+                                               free(dest);
+                                               dest = NULL;
+                                       }
+                                       ERR("iconv is Failed(errno = %d)", errno);
+                                       break;
+                               }
+                       }
+                       dest[dest_len-out_byte] = '\0';
+                       break;
+               }
+               iconv_close(ic);
+               return dest;
+       }
+
+       return NULL;
+}
+
+static char* cts_vcard_get_val(int ver, char *src, char **dest)
+{
+       int len;
+       bool start = false;
+       char *cursor;
+
+       retvm_if(NULL == src, NULL, "The src is NULL.");
+       retvm_if(NULL == dest, NULL, "The dest is NULL.");
+
+       while (*src) {
+               switch (*src) {
+               case '\n':
+                       return NULL;
+               case '\r':
+               case ' ':
+               case ':':
+                       src++;
+                       break;
+               default:
+                       start = true;
+                       break;
+               }
+               if (start) break;
+       }
+
+       cursor = src;
+       len = 0;
+       while (*cursor)
+       {
+               if ('\r' == *cursor) cursor++;
+               if ('\n' == *cursor) {
+                       if (' ' != *(cursor+1))
+                               break;
+               }
+
+               cursor++;
+       }
+
+       if (src == cursor) {
+               *dest = NULL;
+               return NULL;
+       }
+       else {
+               int len = 0;
+               char temp = *cursor;
+               char *new_dest;
+
+               *cursor = '\0';
+               *dest = strdup(src);
+               //if(CTS_VCARD_VER_2_1 == ver)
+               if (cts_vcard_check_quoted(*dest))
+                       len = cts_vcard_decode_quoted_val(*dest);
+               if (0 == len)
+                       len = strlen(*dest);
+               new_dest = cts_vcard_translate_charset(*dest, len);
+               if (new_dest) {
+                       free(*dest);
+                       *dest = new_dest;
+               }
+               *cursor = temp;
+               return (cursor + 1);
+       }
+}
+
+static inline int cts_vcard_check_version(const char *src)
+{
+       bool start = false;
+       const char *ver3 = "3.0";
+
+       while (*src) {
+               switch (*src) {
+               case '\n':
+               case '\r':
+                       return CTS_VCARD_VER_2_1;
+               case ' ':
+                       src++;
+                       break;
+               default:
+                       start = true;
+                       break;
+               }
+               if (start) break;
+       }
+
+       if (0 == strcmp(src, ver3))
+               return CTS_VCARD_VER_3_0;
+       else
+               return CTS_VCARD_VER_2_1;
+}
+
+static inline int cts_vcard_remove_folding(char *folded_src)
+{
+       char *result = folded_src;
+
+       retv_if(NULL == folded_src, CTS_ERR_ARG_NULL);
+
+       while (*folded_src) {
+               if ('\r' == *folded_src)
+                       folded_src++;
+               if ('\n' == *folded_src && ' ' == *(folded_src+1))
+                       folded_src += 2;
+
+               if ('\0' == *folded_src)
+                       break;
+
+               *result = *folded_src;
+               result++;
+               folded_src++;
+       }
+       *result = '\0';
+       return CTS_SUCCESS;
+}
+
+
+static inline char* cts_get_content_value(char *val)
+{
+       char *temp;
+
+       temp = strchr(val, ':');
+       if (temp)
+               temp++;
+       else
+               temp = val;
+
+       retvm_if('\0' == *(temp) || '\r' == *(temp) || '\n' == *(temp),
+               NULL, "Invalid vcard content(%s)", val);
+
+       return temp;
+}
+
+
+static char* cts_strtok(char *val, char c)
+{
+       while(*val) {
+               if(*val == c) {
+                       *val = '\0';
+                       return (val+1);
+               }
+               val++;
+       }
+       return val;
+}
+
+
+static inline int cts_vcard_get_display_name(cts_name *name, char *val)
+{
+       char *temp;
+
+       temp = cts_get_content_value(val);
+       name->display = SAFE_STRDUP(temp);
+
+       return CTS_SUCCESS;
+}
+
+
+static inline int cts_vcard_get_name(cts_name *name, char *val)
+{
+       char *temp, *start;
+       const char separator = ';';
+
+       start = cts_get_content_value(val);
+       retv_if(NULL == start, CTS_ERR_NO_DATA);
+
+       temp = cts_strtok(start, separator);
+       name->last = SMART_STRDUP(start);
+       start = temp;
+       temp = cts_strtok(start, separator);
+       name->first = SMART_STRDUP(start);
+       start = temp;
+       temp = cts_strtok(start, separator);
+       name->addition = SMART_STRDUP(start);
+       start = temp;
+       temp = cts_strtok(start, separator);
+       name->prefix = SMART_STRDUP(start);
+       start = temp;
+       temp = cts_strtok(start, separator);
+       name->suffix = SMART_STRDUP(start);
+
+       return CTS_SUCCESS;
+}
+
+static inline GSList* cts_vcard_get_nickname(GSList *nicks, char *val)
+{
+       char *temp;
+       cts_nickname *result;
+       const char *separator = ",";
+
+       temp = strtok(val, separator);
+       while (temp) {
+               if ('\0' == *temp) continue;
+
+               result = (cts_nickname *)contacts_svc_value_new(CTS_VALUE_NICKNAME);
+               if (result) {
+                       result->embedded = true;
+                       result->nick = strdup(temp);
+                       nicks = g_slist_append(nicks, result);
+               }
+
+               temp = strtok(NULL, separator);
+       }
+
+       return nicks;
+}
+
+static inline GSList* cts_vcard_get_event(GSList *events, int type, char *val)
+{
+       cts_event *event;
+
+       event = (cts_event *)contacts_svc_value_new(CTS_VALUE_EVENT);
+       if (event) {
+               char *dest, *src;
+
+               event->embedded = true;
+               event->type = type;
+
+               dest = src = val;
+               while (*src) {
+                       if ('0' <= *src && *src <= '9') {
+                               *dest = *src;
+                               dest++;
+                       }
+                       src++;
+                       if (8 <= dest - val)
+                               break;
+               }
+               *dest = '\0';
+
+               event->date = atoi(val);
+
+               events = g_slist_append(events, event);
+       }
+
+       return events;
+}
+
+static inline int cts_vcard_get_company(cts_company *org, char *val)
+{
+       char *temp, *start;
+
+       start = cts_get_content_value(val);
+       retv_if(NULL == start, CTS_ERR_NO_DATA);
+
+       temp = strchr(start, ';');
+       if (temp) {
+               *temp = '\0';
+               org->name = SMART_STRDUP(start);
+               org->department = SMART_STRDUP(temp+1);
+       }
+       else
+               org->name = strdup(start);
+
+       return CTS_SUCCESS;
+}
+
+
+static inline char* cts_vcard_get_note(char *val)
+{
+       char *temp;
+
+       temp = cts_get_content_value(val);
+
+       if (temp)
+               return g_strcompress(temp);
+       else
+               return NULL;
+}
+
+
+static inline int cts_vcard_get_time(char *val)
+{
+       int i;
+       char tmp[10];
+       struct tm ts = {0};
+
+       i = 0;
+       while (*val && (*val < '0' || '9' < *val)) val++;
+       while (*val) {
+               tmp[i++] = *val;
+               val++;
+               if (4<=i || *val < '0' || '9' < *val) break;
+       }
+       tmp[i] = 0;
+       ts.tm_year = atoi(tmp)-1900;
+
+       i = 0;
+       while (*val && (*val < '0' || '9' < *val)) val++;
+       while (*val) {
+               tmp[i++] = *val;
+               val++;
+               if (2<=i || *val < '0' || '9' < *val) break;
+       }
+       tmp[i] = 0;
+       ts.tm_mon = atoi(tmp)-1;
+
+       i = 0;
+       while (*val && (*val < '0' || '9' < *val)) val++;
+       while (*val) {
+               tmp[i++] = *val;
+               val++;
+               if (2<=i || *val < '0' || '9' < *val) break;
+       }
+       tmp[i] = 0;
+       ts.tm_mday = atoi(tmp);
+
+       i = 0;
+       while (*val && (*val < '0' || '9' < *val)) val++;
+       while (*val) {
+               tmp[i++] = *val;
+               val++;
+               if (2<=i || *val < '0' || '9' < *val) break;
+       }
+       tmp[i] = 0;
+       ts.tm_hour = atoi(tmp);
+
+       i = 0;
+       while (*val && (*val < '0' || '9' < *val)) val++;
+       while (*val) {
+               tmp[i++] = *val;
+               val++;
+               if (2<=i || *val < '0' || '9' < *val) break;
+       }
+       tmp[i] = 0;
+       ts.tm_min = atoi(tmp);
+
+       i = 0;
+       while (*val && (*val < '0' || '9' < *val)) val++;
+       while (*val) {
+               tmp[i++] = *val;
+               val++;
+               if (2<=i || *val < '0' || '9' < *val) break;
+       }
+       tmp[i] = 0;
+       ts.tm_sec = atoi(tmp);
+
+       return (int)mktime(&ts);
+}
+
+
+static inline GSList* cts_vcard_get_web(GSList *webs, char *val)
+{
+       cts_web *web;
+       char *temp;
+
+       temp = cts_get_content_value(val);
+       retvm_if(NULL == temp, webs, "Invalid vcard(%s)", val);
+
+       web = (cts_web *)contacts_svc_value_new(CTS_VALUE_WEB);
+       if (web) {
+               web->embedded = true;
+               web->url = strdup(temp);;
+               if (val != temp) {
+                       *(temp-1) = '\0';
+                       temp = val;
+                       while (*temp)
+                       {
+                               *temp = tolower(*temp);
+                               temp++;
+                       }
+
+                       temp = strchr(val, ';');
+                       if (temp) {
+                               if (strstr(val, "home"))
+                                       web->type = CTS_WEB_TYPE_HOME;
+                               else if (strstr(val, "work"))
+                                       web->type = CTS_WEB_TYPE_WORK;
+                       }
+               }
+               webs = g_slist_append(webs, web);
+       } else {
+               ERR("contacts_svc_value_new() Failed");
+       }
+
+       return webs;
+}
+
+
+static inline bool cts_vcard_get_number_type(cts_number *number, char *val)
+{
+       char *temp, *result;
+       int type = CTS_NUM_TYPE_NONE;
+       bool pref = false;
+
+       temp = val;
+       while (*temp)
+       {
+               *temp = tolower(*temp);
+               temp++;
+       }
+
+       temp = strchr(val , ';');
+       if (temp) {
+               result = strstr(val, "home");
+               if (result) type |= CTS_NUM_TYPE_HOME;
+               result = strstr(val, "msg");
+               if (result) type |= CTS_NUM_TYPE_MSG;
+               result = strstr(val, "work");
+               if (result) type |= CTS_NUM_TYPE_WORK;
+               result = strstr(val, "pref");
+               if (result) pref = true;
+               result = strstr(val, "voice");
+               if (result) type |= CTS_NUM_TYPE_VOICE;
+               result = strstr(val, "fax");
+               if (result) type |= CTS_NUM_TYPE_FAX;
+               result = strstr(val, "cell");
+               if (result) type |= CTS_NUM_TYPE_CELL;
+               result = strstr(val, "video");
+               if (result) type |= CTS_NUM_TYPE_VIDEO;
+               result = strstr(val, "pager");
+               if (result) type |= CTS_NUM_TYPE_PAGER;
+               result = strstr(val, "bbs");
+               if (result) type |= CTS_NUM_TYPE_BBS;
+               result = strstr(val, "modem");
+               if (result) type |= CTS_NUM_TYPE_MODEM;
+               result = strstr(val, "car");
+               if (result) type |= CTS_NUM_TYPE_CAR;
+               result = strstr(val, "isdn");
+               if (result) type |= CTS_NUM_TYPE_ISDN;
+               result = strstr(val, "pcs");
+               if (result) type |= CTS_NUM_TYPE_PCS;
+       }
+       number->type = type;
+
+       return pref;
+}
+
+
+static inline GSList* cts_vcard_get_number(GSList *numbers, char *val)
+{
+       cts_number *number;
+       char *temp;
+
+       temp = cts_get_content_value(val);
+       retvm_if(NULL == temp, numbers, "Invalid vcard(%s)", val);
+
+       number = (cts_number *)contacts_svc_value_new(CTS_VALUE_NUMBER);
+       if (number) {
+               number->embedded = true;
+               number->number = strdup(temp);
+               if (val != temp) {
+                       *(temp-1) = '\0';
+                       number->is_default = cts_vcard_get_number_type(number, val);
+               }
+               numbers = g_slist_append(numbers, number);
+       } else {
+               ERR("contacts_svc_value_new() Failed");
+       }
+
+       return numbers;
+}
+
+static inline bool cts_vcard_get_email_type(cts_email *email, char *val)
+{
+       char *temp;
+       int type = CTS_EMAIL_TYPE_NONE;
+       bool pref = false;
+
+       temp = val;
+       while (*temp)
+       {
+               *temp = tolower(*temp);
+               temp++;
+       }
+
+       temp = strchr(val , ';');
+       if (temp) {
+               if (strstr(val, "home"))
+                       type = CTS_EMAIL_TYPE_HOME;
+               else if (strstr(val, "work"))
+                       type = CTS_EMAIL_TYPE_WORK;
+               if (strstr(val, "pref"))
+                       pref = true;
+       }
+       email->type = type;
+
+       return pref;
+}
+
+static inline GSList* cts_vcard_get_email(GSList *emails, char *val)
+{
+       cts_email *email;
+       char *temp;
+
+       temp = cts_get_content_value(val);
+       retvm_if(NULL == temp, emails, "Invalid vcard(%s)", val);
+
+       email = (cts_email *)contacts_svc_value_new(CTS_VALUE_EMAIL);
+       if (email) {
+               email->embedded = true;
+               email->email_addr = strdup(temp);
+               if (val != temp) {
+                       *(temp-1) = '\0';
+                       email->is_default = cts_vcard_get_email_type(email, val);
+               }
+               emails = g_slist_append(emails, email);
+       } else {
+               ERR("contacts_svc_value_new() Failed");
+       }
+
+       return emails;
+}
+
+static inline bool cts_vcard_get_postal_type(cts_postal *postal, char *val)
+{
+       char *temp, *result;
+       int type = CTS_ADDR_TYPE_NONE;
+       bool pref = false;
+
+       temp = val;
+       while (*temp)
+       {
+               *temp = tolower(*temp);
+               temp++;
+       }
+
+       temp = strchr(val , ';');
+       if (temp) {
+               result = strstr(val, "dom");
+               if (result) type |= CTS_ADDR_TYPE_DOM;
+               result = strstr(val, "intl");
+               if (result) type |= CTS_ADDR_TYPE_INTL;
+               result = strstr(val, "postal");
+               if (result) type |= CTS_ADDR_TYPE_POSTAL;
+               result = strstr(val, "parcel");
+               if (result) type |= CTS_ADDR_TYPE_PARCEL;
+               result = strstr(val, "home");
+               if (result) type |= CTS_ADDR_TYPE_HOME;
+               result = strstr(val, "work");
+               if (result) type |= CTS_ADDR_TYPE_WORK;
+               result = strstr(val, "pref");
+               if (result) pref = true;
+       }
+       postal->type = type;
+
+       return pref;
+}
+
+#define CTS_GET_ADDR_COMPONENT(dest, src, tmp_char) \
+       tmp_char = strchr(src , ';'); \
+if (tmp_char) { \
+       *tmp_char = '\0'; \
+       dest = SMART_STRDUP(src); \
+       src = tmp_char+1; \
+} \
+else { \
+       dest = SMART_STRDUP(src); \
+       break; \
+} \
+
+static inline GSList* cts_vcard_get_postal(GSList *postals, char *val)
+{
+       char *text;
+       cts_postal *postal;
+
+       postal = (cts_postal *)contacts_svc_value_new(CTS_VALUE_POSTAL);
+       if (postal) {
+               postal->embedded = true;
+
+               text = strrchr(val , ':');
+               if (text)
+                       text++;
+               else
+                       text = val;
+
+               while (true) {
+                       char *temp;
+
+                       CTS_GET_ADDR_COMPONENT(postal->pobox, text, temp);
+                       CTS_GET_ADDR_COMPONENT(postal->extended, text, temp);
+                       CTS_GET_ADDR_COMPONENT(postal->street, text, temp);
+                       CTS_GET_ADDR_COMPONENT(postal->locality, text, temp);
+                       CTS_GET_ADDR_COMPONENT(postal->region, text, temp);
+                       CTS_GET_ADDR_COMPONENT(postal->postalcode, text, temp);
+                       CTS_GET_ADDR_COMPONENT(postal->country, text, temp);
+
+                       ERR("invalid ADR type(%s)", temp);
+                       break;
+               }
+               if (postal->pobox || postal->extended || postal->street || postal->locality
+                               || postal->region || postal->postalcode || postal->country) {
+                       postal->is_default = cts_vcard_get_postal_type(postal, val);
+               } else {
+                       ERR("Invalid vcard(%s)", val);
+                       contacts_svc_value_free((CTSvalue *)postal);
+                       return postals;
+               }
+
+               postals = g_slist_append(postals, postal);
+       }
+
+       return postals;
+}
+
+static inline int cts_vcard_get_photo_type(char *val)
+{
+       char *temp, *result;
+
+       temp = val;
+       while (*temp)
+       {
+               *temp = tolower(*temp);
+               temp++;
+       }
+
+       result = strstr(val, "jpeg");
+       if (result) return CTS_VCARD_IMG_JPEG;
+       result = strstr(val, "jpg");
+       if (result) return CTS_VCARD_IMG_JPEG;
+
+       result = strstr(val, "png");
+       if (result) return CTS_VCARD_IMG_PNG;
+
+       result = strstr(val, "gif");
+       if (result) return CTS_VCARD_IMG_GIF;
+
+       result = strstr(val, "tiff");
+       if (result) return CTS_VCARD_IMG_TIFF;
+
+       return CTS_VCARD_IMG_NONE;
+}
+
+static inline const char* cts_get_img_suffix(int type)
+{
+       switch (type)
+       {
+       case CTS_VCARD_IMG_TIFF:
+               return "tiff";
+       case CTS_VCARD_IMG_GIF:
+               return "gif";
+       case CTS_VCARD_IMG_PNG:
+               return "png";
+       case CTS_VCARD_IMG_JPEG:
+       case CTS_VCARD_IMG_NONE:
+       default:
+               return "jpeg";
+       }
+}
+
+static inline int cts_vcard_get_photo(cts_ct_base *base, char *val)
+{
+       int ret, type, fd;
+       gsize size;
+       guchar *buf;
+       char *temp;
+       char dest[CTS_IMG_PATH_SIZE_MAX];
+
+       temp = strchr(val , ':');
+       retvm_if(NULL == temp, CTS_ERR_ARG_INVALID, "val is invalid(%s)", val);
+
+       *temp = '\0';
+       type = cts_vcard_get_photo_type(val);
+
+       ret = snprintf(dest, sizeof(dest), "%s/%d-%d.%s", CTS_VCARD_IMAGE_LOCATION,
+                       getpid(), cts_tmp_photo_id++, cts_get_img_suffix(type));
+       retvm_if(ret<=0, CTS_ERR_FAIL, "Destination file name was not created");
+
+       fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, 0660);
+       retvm_if(fd < 0, CTS_ERR_FAIL, "open(%s) Failed(%d)", dest, errno);
+
+       buf = g_base64_decode(temp+1, &size);
+
+       while (0 < size) {
+               ret = write(fd, buf, size);
+               if (ret <= 0) {
+                       if (EINTR == errno)
+                               continue;
+                       else {
+                               ERR("write() Failed(%d)", errno);
+                               close(fd);
+                               if (ENOSPC == errno)
+                                       return CTS_ERR_NO_SPACE;
+                               else
+                                       return CTS_ERR_IO_ERR;
+                       }
+               }
+               size -= ret;
+       }
+
+       close(fd);
+       g_free(buf);
+
+       base->vcard_img_path = strdup(dest);
+
+       return CTS_SUCCESS;
+}
+
+static inline GSList* cts_vcard_get_group(GSList *groups, char *val)
+{
+       char *temp;
+       cts_group *result;
+       const char *separator = ",";
+
+       temp = strtok(val, separator);
+       while (temp) {
+               if ('\0' == *temp) continue;
+
+               result = (cts_group *)contacts_svc_value_new(CTS_VALUE_GROUP_RELATION);
+               if (result) {
+                       result->embedded = true;
+                       result->vcard_group = strdup(temp);
+                       groups = g_slist_append(groups, result);
+               }
+
+               temp = strtok(NULL, separator);
+       }
+
+       return groups;
+}
+
+static inline char* cts_vcard_pass_unsupported(char *vcard)
+{
+       while (*vcard) {
+               if ('\n' == *vcard)
+                       return (vcard + 1);
+               vcard++;
+       }
+
+       return NULL;
+}
+
+static inline int cts_vcard_get_contact(int ver, int flags,
+               char *vcard, contact_t *contact)
+{
+       int type;
+       char *cursor, *new_start, *val;
+
+       cursor = vcard;
+       while (cursor)
+       {
+               type = cts_vcard_check_content_type(&cursor);
+               if (CTS_VCARD_VALUE_NONE == type) {
+                       new_start = cts_vcard_pass_unsupported(cursor);
+                       if (new_start) {
+                               cursor = new_start;
+                               continue;
+                       }
+                       else
+                               break;
+               }
+
+               new_start = cts_vcard_get_val(ver, cursor, &val);
+               if (NULL == new_start)
+                       continue;
+
+               if (NULL == val) {
+                       cursor = new_start;
+                       continue;
+               }
+               cts_vcard_remove_folding(val);
+
+               switch (type) {
+               case CTS_VCARD_VALUE_FN:
+                       cts_vcard_get_display_name(contact->name, val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_N:
+                       cts_vcard_get_name(contact->name, val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_NICKNAME:
+                       contact->nicknames = cts_vcard_get_nickname(contact->nicknames, val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_PHOTO:
+                       cts_vcard_get_photo(contact->base, val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_BDAY:
+                       contact->events = cts_vcard_get_event(contact->events,
+                                       CTS_EVENT_TYPE_BIRTH, val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_ADR:
+               case CTS_VCARD_VALUE_LABEL:
+                       contact->postal_addrs = cts_vcard_get_postal(contact->postal_addrs, val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_TEL:
+                       contact->numbers = cts_vcard_get_number(contact->numbers, val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_EMAIL:
+                       contact->emails = cts_vcard_get_email(contact->emails, val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_TITLE:
+                       if (NULL == contact->company) {
+                               contact->company = (cts_company*)contacts_svc_value_new(CTS_VALUE_COMPANY);
+                               if (NULL == contact->company) {
+                                       free(val);
+                                       ERR("contacts_svc_value_new(CTS_VALUE_COMPANY) Failed");
+                                       return CTS_ERR_OUT_OF_MEMORY;
+                               }
+                               contact->company->embedded = true;
+                       }
+                       contact->company->jot_title = val;
+                       break;
+               case CTS_VCARD_VALUE_ROLE:
+                       if (NULL == contact->company) {
+                               contact->company = (cts_company*)contacts_svc_value_new(CTS_VALUE_COMPANY);
+                               if (NULL == contact->company) {
+                                       free(val);
+                                       ERR("contacts_svc_value_new(CTS_VALUE_COMPANY) Failed");
+                                       return CTS_ERR_OUT_OF_MEMORY;
+                               }
+                               contact->company->embedded = true;
+                       }
+                       contact->company->role = val;
+                       break;
+               case CTS_VCARD_VALUE_ORG:
+                       if (NULL == contact->company) {
+                               contact->company = (cts_company*)contacts_svc_value_new(CTS_VALUE_COMPANY);
+                               if (NULL == contact->company) {
+                                       free(val);
+                                       ERR("contacts_svc_value_new(CTS_VALUE_COMPANY) Failed");
+                                       return CTS_ERR_OUT_OF_MEMORY;
+                               }
+                               contact->company->embedded = true;
+                       }
+                       cts_vcard_get_company(contact->company, val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_NOTE:
+                       contact->base->note = cts_vcard_get_note(val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_REV:
+                       if (*val)
+                               contact->base->changed_time = cts_vcard_get_time(val);;
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_UID:
+                       contact->base->uid = val;
+                       break;
+               case CTS_VCARD_VALUE_URL:
+                       contact->web_addrs = cts_vcard_get_web(contact->web_addrs, val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_X_ANNIVERSARY:
+                       contact->events = cts_vcard_get_event(contact->events,
+                                       CTS_EVENT_TYPE_ANNIVERSARY, val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_X_IRMC_LUID:
+                       contact->base->id = atoi(val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_X_SLP_GROUP:
+                       if (flags & CTS_VCARD_CONTENT_X_SLP_GROUP)
+                               contact->grouprelations = cts_vcard_get_group(contact->grouprelations, val);
+                       free(val);
+                       break;
+               case CTS_VCARD_VALUE_END:
+                       free(val);
+                       return CTS_SUCCESS;
+               default:
+                       ERR("cts_vcard_check_content_type() Failed(%d)", type);
+                       return CTS_ERR_VOBJECT_FAILED;
+               }
+               cursor = new_start;
+       }
+
+       ERR("Invalid vcard(%s)", vcard);
+       return CTS_ERR_ARG_INVALID;
+}
+
+static void cts_vcard_initial(void)
+{
+       if (NULL == *content_name) {
+               //content_name[CTS_VCARD_VALUE_NAME] = "NAME"; /* not supported */
+               //content_name[CTS_VCARD_VALUE_PROFILE] = "PROFILE"; /* not supported */
+               //content_name[CTS_VCARD_VALUE_SOURCE] = "SOURCE"; /* not supported */
+               content_name[CTS_VCARD_VALUE_FN] = "FN";
+               content_name[CTS_VCARD_VALUE_N] = "N";
+               content_name[CTS_VCARD_VALUE_NICKNAME] = "NICKNAME";
+               content_name[CTS_VCARD_VALUE_PHOTO] = "PHOTO";
+               content_name[CTS_VCARD_VALUE_BDAY] = "BDAY";
+               content_name[CTS_VCARD_VALUE_ADR] = "ADR";
+               content_name[CTS_VCARD_VALUE_LABEL] = "LABEL"; /* not supported */
+               content_name[CTS_VCARD_VALUE_TEL] = "TEL";
+               content_name[CTS_VCARD_VALUE_EMAIL] = "EMAIL";
+               //content_name[CTS_VCARD_VALUE_MAILER] = "MAILER"; /* not supported */
+               //content_name[CTS_VCARD_VALUE_TZ] = "TZ"; /* not supported */
+               //content_name[CTS_VCARD_VALUE_GEO] = "GEO"; /* not supported */
+               content_name[CTS_VCARD_VALUE_TITLE] = "TITLE";
+               content_name[CTS_VCARD_VALUE_ROLE] = "ROLE";
+               //content_name[CTS_VCARD_VALUE_LOGO] = "LOGO"; /* not supported */
+               //content_name[CTS_VCARD_VALUE_AGENT] = "AGENT"; /* not supported */
+               content_name[CTS_VCARD_VALUE_ORG] = "ORG";
+               //content_name[CTS_VCARD_VALUE_CATEGORIES] = "CATEGORIES"; /* not supported */
+               content_name[CTS_VCARD_VALUE_NOTE] = "NOTE";
+               //content_name[CTS_VCARD_VALUE_PRODID] = "PRODID"; /* not supported */
+               content_name[CTS_VCARD_VALUE_REV] = "REV";
+               //content_name[CTS_VCARD_VALUE_SORT-STRING] = "SORT-STRING"; /* not supported */
+               //content_name[CTS_VCARD_VALUE_SOUND] = "SOUND"; /* not supported */
+               content_name[CTS_VCARD_VALUE_UID] = "UID";
+               content_name[CTS_VCARD_VALUE_URL] = "URL";
+               //content_name[CTS_VCARD_VALUE_VERSION] = "VERSION"; /* not supported */
+               //content_name[CTS_VCARD_VALUE_CLASS] = "CLASS";         /* not supported */
+               //content_name[CTS_VCARD_VALUE_KEY] = "KEY"; /* not supported */
+               content_name[CTS_VCARD_VALUE_X_ANNIVERSARY] = "X-ANNIVERSARY";
+               //content_name[CTS_VCARD_VALUE_X_CHILDREN] = "X-CHILDREN";
+               content_name[CTS_VCARD_VALUE_X_IRMC_LUID] = "X-IRMC-LUID";
+               content_name[CTS_VCARD_VALUE_X_SLP_GROUP] = "X-SLP-GROUP";
+               content_name[CTS_VCARD_VALUE_END] = "END";
+       }
+};
+
+int cts_vcard_parse(const void *vcard_stream, CTSstruct **contact, int flags)
+{
+       int ret, ver;
+       contact_t *result;
+       char *val_begin, *new_start, *val;
+       char *vcard = (char *)vcard_stream;
+
+       retv_if(NULL == vcard_stream, CTS_ERR_ARG_NULL);
+
+       cts_vcard_initial();
+
+       vcard = cts_vcard_check_word(vcard, "BEGIN:VCARD");
+       retvm_if(NULL == vcard, CTS_ERR_ARG_INVALID, "The vcard is invalid.");
+
+       val_begin = cts_vcard_check_word(vcard, "VERSION:");
+       new_start = cts_vcard_get_val(CTS_VCARD_VER_NONE, val_begin, &val);
+       if (NULL == new_start || NULL == val)
+               ver = CTS_VCARD_VER_2_1;
+       else {
+               ver = cts_vcard_check_version(val);
+               free(val);
+               vcard = new_start;
+       }
+
+       result = (contact_t *)contacts_svc_struct_new(CTS_STRUCT_CONTACT);
+       retvm_if(NULL == result, CTS_ERR_OUT_OF_MEMORY, "contacts_svc_struct_new() Failed");
+
+       result->name = (cts_name*)contacts_svc_value_new(CTS_VALUE_NAME);
+       if (NULL == result->name) {
+               ERR("contacts_svc_value_new(CTS_VALUE_NAME) Failed");
+               contacts_svc_struct_free((CTSstruct *)result);
+               return CTS_ERR_OUT_OF_MEMORY;
+       }
+       result->name->embedded = true;
+
+       result->base = (cts_ct_base*)contacts_svc_value_new(CTS_VALUE_CONTACT_BASE_INFO);
+       if (NULL == result->base) {
+               ERR("contacts_svc_value_new(CTS_VALUE_CONTACT_BASE_INFO) Failed");
+               contacts_svc_struct_free((CTSstruct *)result);
+               return CTS_ERR_OUT_OF_MEMORY;
+       }
+       result->base->embedded = true;
+
+       ret = cts_vcard_get_contact(ver, flags, vcard, result);
+
+       if (CTS_SUCCESS != ret) {
+               contacts_svc_struct_free((CTSstruct *)result);
+               if (CTS_ERR_ARG_INVALID == ret)
+                       ERR("cts_vcard_get_contact() Failed(%d)\n %s \n", ret, vcard);
+               else
+                       ERR("cts_vcard_get_contact() Failed(%d)", ret);
+
+               return ret;
+       }
+
+       *contact = (CTSstruct *)result;
+       return CTS_SUCCESS;
+}
+
+/**************************
+ *
+ * Contact To VCard
+ *
+ **************************/
+
+const char *CTS_CRLF = "\r\n";
+
+static inline int cts_vcard_append_name(cts_name *name,
+               char *dest, int dest_size)
+{
+       int ret_len;
+       ret_len = snprintf(dest, dest_size, "%s", content_name[CTS_VCARD_VALUE_N]);
+       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ":%s",
+                       SAFE_STR(name->last));
+       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s",
+                       SAFE_STR(name->first));
+       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s",
+                       SAFE_STR(name->addition));
+       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s",
+                       SAFE_STR(name->prefix));
+       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s%s",
+                       SAFE_STR(name->suffix), CTS_CRLF);
+
+       if (name->display)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s:%s%s",
+                               content_name[CTS_VCARD_VALUE_FN],
+                               name->display, CTS_CRLF);
+       else {
+               char display[1024];
+
+               if (name->first && name->last) {
+                       if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_SORTING)) {
+                               snprintf(display, sizeof(display), "%s %s", name->first, name->last);
+                       } else {
+                               int lang;
+                               if (CTS_LANG_DEFAULT == name->lang_type)
+                                       lang = cts_get_default_language();
+                               else
+                                       lang = name->lang_type;
+
+                               if (CTS_LANG_ENGLISH == lang)
+                                       snprintf(display, sizeof(display), "%s, %s", name->last, name->first);
+                               else
+                                       snprintf(display, sizeof(display), "%s %s", name->last, name->first);
+                       }
+               }
+               else
+                       snprintf(display, sizeof(display), "%s%s", SAFE_STR(name->first), SAFE_STR(name->last));
+
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s:%s%s",
+                               content_name[CTS_VCARD_VALUE_FN],
+                               display, CTS_CRLF);
+       }
+
+       return ret_len;
+}
+
+static inline int cts_vcard_put_number_type(int type, char *dest, int dest_size)
+{
+       int ret_len = 0;
+       if (type & CTS_NUM_TYPE_HOME)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "HOME");
+       if (type & CTS_NUM_TYPE_MSG)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "MSG");
+       if (type & CTS_NUM_TYPE_WORK)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "WORK");
+       if (type & CTS_NUM_TYPE_VOICE)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "VOICE");
+       if (type & CTS_NUM_TYPE_FAX)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "FAX");
+       if (type & CTS_NUM_TYPE_VOICE)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "VOICE");
+       if (type & CTS_NUM_TYPE_CELL)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "CELL");
+       if (type & CTS_NUM_TYPE_VIDEO)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "VIDEO");
+       if (type & CTS_NUM_TYPE_PAGER)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "PAGER");
+       if (type & CTS_NUM_TYPE_BBS)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "BBS");
+       if (type & CTS_NUM_TYPE_MODEM)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "MODEM");
+       if (type & CTS_NUM_TYPE_CAR)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "CAR");
+       if (type & CTS_NUM_TYPE_ISDN)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "ISDN");
+       if (type & CTS_NUM_TYPE_PCS)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "PCS");
+
+       return ret_len;
+}
+
+static inline int cts_vcard_append_numbers(GSList *numbers,
+               char *dest, int dest_size)
+{
+       int ret_len = 0;
+       GSList *cursor;
+       cts_number *data;
+
+       for (cursor=numbers;cursor;cursor=cursor->next) {
+               data = cursor->data;
+               if (data->number) {
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s",
+                                       content_name[CTS_VCARD_VALUE_TEL]);
+                       ret_len += cts_vcard_put_number_type(data->type, dest+ret_len,
+                                       dest_size-ret_len);
+                       if (data->is_default)
+                               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "PREF");
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ":%s%s",
+                                       data->number, CTS_CRLF);
+               }
+       }
+
+       return ret_len;
+}
+
+static inline int cts_vcard_append_emails(GSList *emails,
+               char *dest, int dest_size)
+{
+       int ret_len = 0;
+       GSList *cursor;
+       cts_email *data;
+
+       for (cursor=emails;cursor;cursor=cursor->next) {
+               data = cursor->data;
+               if (data->email_addr) {
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s",
+                                       content_name[CTS_VCARD_VALUE_EMAIL]);
+                       if (CTS_EMAIL_TYPE_HOME & data->type)
+                               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "HOME");
+                       if (CTS_EMAIL_TYPE_WORK & data->type)
+                               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "WORK");
+
+                       if (data->is_default)
+                               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "PREF");
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ":%s%s",
+                                       data->email_addr, CTS_CRLF);
+               }
+       }
+
+       return ret_len;
+}
+
+static inline int cts_vcard_put_postal_type(int type, char *dest, int dest_size)
+{
+       int ret_len = 0;
+       if (type & CTS_ADDR_TYPE_DOM)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "DOM");
+       if (type & CTS_ADDR_TYPE_INTL)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "INTL");
+       if (type & CTS_ADDR_TYPE_HOME)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "HOME");
+       if (type & CTS_ADDR_TYPE_WORK)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "WORK");
+       if (type & CTS_ADDR_TYPE_POSTAL)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "POSTAL");
+       if (type & CTS_ADDR_TYPE_PARCEL)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "PARCEL");
+
+       return ret_len;
+}
+
+static inline int cts_vcard_append_postals(GSList *numbers,
+               char *dest, int dest_size)
+{
+       int ret_len = 0;
+       GSList *cursor;
+       cts_postal *data;
+
+       for (cursor=numbers;cursor;cursor=cursor->next) {
+               data = cursor->data;
+               if (data) {
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s",
+                                       content_name[CTS_VCARD_VALUE_ADR]);
+                       ret_len += cts_vcard_put_postal_type(data->type, dest+ret_len,
+                                       dest_size-ret_len);
+                       if (data->is_default)
+                               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s", "PREF");
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ":%s",
+                                       SAFE_STR(data->pobox));
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s",
+                                       SAFE_STR(data->extended));
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s",
+                                       SAFE_STR(data->street));
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s",
+                                       SAFE_STR(data->locality));
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s",
+                                       SAFE_STR(data->region));
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s",
+                                       SAFE_STR(data->postalcode));
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s%s",
+                                       SAFE_STR(data->country), CTS_CRLF);
+               }
+       }
+
+       return ret_len;
+}
+
+static inline int cts_vcard_append_company(cts_company *org,
+               char *dest, int dest_size)
+{
+       int ret_len = 0;
+
+       ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s:%s",
+                       content_name[CTS_VCARD_VALUE_ORG],
+                       SAFE_STR(org->name));
+       if (org->department)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ";%s",
+                               org->department);
+
+       ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s", CTS_CRLF);
+
+       if (org->jot_title)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s:%s%s",
+                               content_name[CTS_VCARD_VALUE_TITLE],
+                               org->jot_title, CTS_CRLF);
+       if (org->role)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s:%s%s",
+                               content_name[CTS_VCARD_VALUE_ROLE],
+                               org->role, CTS_CRLF);
+
+       return ret_len;
+}
+
+static inline int cts_vcard_append_nicks(GSList *nicks,
+               char *dest, int dest_size)
+{
+       bool first;
+       int ret_len = 0;
+       GSList *cursor;
+       cts_nickname *data;
+
+       ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s:",
+                       content_name[CTS_VCARD_VALUE_NICKNAME]);
+
+       first = true;
+       for (cursor=nicks;cursor;cursor=cursor->next) {
+               data = cursor->data;
+               if (data->nick && *data->nick) {
+                       if (first) {
+                               ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s", data->nick);
+                               first = false;
+                       }
+                       else {
+                               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ",%s", data->nick);
+                       }
+               }
+       }
+
+       ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s", CTS_CRLF);
+
+       return ret_len;
+}
+
+static inline int cts_vcard_append_webs(GSList *webs,
+               char *dest, int dest_size)
+{
+       int ret_len = 0;
+       GSList *cursor;
+       cts_web *data;
+
+       for (cursor=webs;cursor;cursor=cursor->next) {
+               data = cursor->data;
+               if (data->url && *data->url) {
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s:%s%s",
+                                       content_name[CTS_VCARD_VALUE_URL],
+                                       data->url, CTS_CRLF);
+               }
+       }
+
+       return ret_len;
+}
+
+static inline int cts_vcard_append_events(GSList *webs,
+               char *dest, int dest_size)
+{
+       int ret_len = 0;
+       GSList *cursor;
+       cts_event *data;
+
+       for (cursor=webs;cursor;cursor=cursor->next) {
+               data = cursor->data;
+               if (!data->date) continue;
+
+               if (CTS_EVENT_TYPE_BIRTH == data->type) {
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s:%d-%02d-%d%s",
+                                       content_name[CTS_VCARD_VALUE_BDAY],
+                                       data->date/10000, (data->date%10000)/100, data->date%100,
+                                       CTS_CRLF);
+               }
+               else if (CTS_EVENT_TYPE_ANNIVERSARY == data->type) {
+                       ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s:%d-%02d-%d%s",
+                                       content_name[CTS_VCARD_VALUE_X_ANNIVERSARY],
+                                       data->date/10000, (data->date%10000)/100, data->date%100,
+                                       CTS_CRLF);
+               }
+       }
+
+       return ret_len;
+}
+
+static inline const char* cts_get_photo_type_str(int type)
+{
+       switch (type)
+       {
+       case CTS_VCARD_IMG_TIFF:
+               return "TIFF";
+       case CTS_VCARD_IMG_GIF:
+               return "GIF";
+       case CTS_VCARD_IMG_PNG:
+               return "PNG";
+       case CTS_VCARD_IMG_JPEG:
+       default:
+               return "JPEG";
+       }
+}
+
+static inline int cts_vcard_put_photo(const char *path, char *dest, int dest_size)
+{
+       int ret, fd, type;
+       gsize read_len;
+       char *suffix;
+       gchar *buf;
+       guchar image[CTS_VCARD_PHOTO_MAX_SIZE];
+
+       suffix = strrchr(path, '.');
+       retvm_if(NULL == suffix, 0, "Image Type(%s) is invalid", path);
+
+       type = cts_vcard_get_photo_type(suffix);
+       retvm_if(CTS_VCARD_IMG_NONE == type, 0, "Image Type(%s) is invalid", path);
+
+       fd = open(path, O_RDONLY);
+       retvm_if(fd < 0, 0, "Open(%s) Failed(%d)", path, errno);
+
+       read_len = 0;
+       while ((ret=read(fd, image+read_len, sizeof(image)-read_len))) {
+               if (-1 == ret) {
+                       if (EINTR == errno)
+                               continue;
+                       else
+                               break;
+               }
+               read_len += ret;
+       }
+       close(fd);
+       retvm_if(ret < 0, 0, "read() Failed(%d)", errno);
+
+       ret = 0;
+       buf = g_base64_encode(image, read_len);
+       if (buf) {
+               ret = snprintf(dest, dest_size, "%s;ENCODING=BASE64;TYPE=%s:%s%s%s",
+                               content_name[CTS_VCARD_VALUE_PHOTO],
+                               cts_get_photo_type_str(type), buf, CTS_CRLF, CTS_CRLF);
+               g_free(buf);
+       }
+
+       return ret;
+}
+static inline int cts_vcard_append_base(cts_ct_base *base,
+               char *dest, int dest_size)
+{
+       int ret_len = 0;
+
+       if (base->img_path)
+               ret_len += cts_vcard_put_photo(base->img_path,
+                               dest+ret_len, dest_size-ret_len);
+       if (base->uid)
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s:%s%s",
+                               content_name[CTS_VCARD_VALUE_UID],
+                               base->uid, CTS_CRLF);
+       if (base->note) {
+               gchar *escaped_note;
+               escaped_note = g_strescape(base->note, NULL);
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s:%s%s",
+                               content_name[CTS_VCARD_VALUE_NOTE],
+                               escaped_note, CTS_CRLF);
+               g_free(escaped_note);
+       }
+
+       if (base->changed_time) {
+               struct tm ts;
+               gmtime_r((time_t *)&base->changed_time, &ts);
+               ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s:%04d-%02d-%02dT%02d:%02d:%02dZ%s",
+                               content_name[CTS_VCARD_VALUE_REV],
+                               1900+ts.tm_year, 1+ts.tm_mon, ts.tm_mday,
+                               ts.tm_hour, ts.tm_min, ts.tm_sec,
+                               CTS_CRLF);
+       }
+
+       return ret_len;
+}
+
+static inline int cts_vcard_append_grouprelations(GSList *grouprelations,
+               char *dest, int dest_size)
+{
+       bool first;
+       int ret_len = 0;
+       GSList *cursor;
+       cts_group *data;
+
+       ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s:",
+                       content_name[CTS_VCARD_VALUE_X_SLP_GROUP]);
+
+       first = true;
+       for (cursor=grouprelations;cursor;cursor=cursor->next) {
+               data = cursor->data;
+               if (data->name && *data->name) {
+                       if (first) {
+                               ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s", data->name);
+                               first = false;
+                       }
+                       else {
+                               ret_len += snprintf(dest+ret_len, dest_size-ret_len, ",%s", data->name);
+                       }
+               }
+       }
+
+       ret_len += snprintf(dest+ret_len, dest_size-ret_len, "%s", CTS_CRLF);
+
+       return ret_len;
+}
+
+static inline int cts_vcard_append_contact(int flags, contact_t *contact,
+               char *dest, int dest_size)
+{
+       int ret_len = 0;
+
+       if (contact->name)
+               ret_len += cts_vcard_append_name(contact->name,
+                               dest+ret_len, dest_size-ret_len);
+       if (contact->company)
+               ret_len += cts_vcard_append_company(contact->company,
+                               dest+ret_len, dest_size-ret_len);
+       if (contact->postal_addrs)
+               ret_len += cts_vcard_append_postals(contact->postal_addrs,
+                               dest+ret_len, dest_size-ret_len);
+       if (contact->numbers)
+               ret_len += cts_vcard_append_numbers(contact->numbers,
+                               dest+ret_len, dest_size-ret_len);
+       if (contact->emails)
+               ret_len += cts_vcard_append_emails(contact->emails,
+                               dest+ret_len, dest_size-ret_len);
+       if (contact->nicknames)
+               ret_len += cts_vcard_append_nicks(contact->nicknames,
+                               dest+ret_len, dest_size-ret_len);
+       if (contact->web_addrs)
+               ret_len += cts_vcard_append_webs(contact->web_addrs,
+                               dest+ret_len, dest_size-ret_len);
+       if (contact->events)
+               ret_len += cts_vcard_append_events(contact->events,
+                               dest+ret_len, dest_size-ret_len);
+       if (contact->base)
+               ret_len += cts_vcard_append_base(contact->base,
+                               dest+ret_len, dest_size-ret_len);
+       if (contact->grouprelations && (flags & CTS_VCARD_CONTENT_X_SLP_GROUP))
+               ret_len += cts_vcard_append_grouprelations(contact->grouprelations,
+                               dest+ret_len, dest_size-ret_len);
+
+       return ret_len;
+}
+
+#define CTS_VCARD_FOLDING_LIMIT 75
+
+static inline int cts_vcard_add_folding(char *src)
+{
+       int len, result_len;
+       char result[CTS_VCARD_FILE_MAX_SIZE];
+       char *r;
+       const char *s;
+
+       s = src;
+       r = result;
+       len = result_len = 0;
+       while (*s) {
+               if ('\r' == *s)
+                       len--;
+               else if ('\n' == *s)
+                       len = -1;
+
+               if (CTS_VCARD_FOLDING_LIMIT == len) {
+                       *r = '\r';
+                       r++;
+                       *r = '\n';
+                       r++;
+                       *r = ' ';
+                       r++;
+                       len = 1;
+                       result_len += 3;
+               }
+
+               *r = *s;
+               r++;
+               s++;
+               len++;
+               result_len++;
+               retvm_if(sizeof(result) - 5 < result_len, CTS_ERR_ARG_INVALID,
+                               "src is too long\n(%s)", src);
+       }
+       *r = '\0';
+
+       memcpy(src, result, result_len+1);
+       return CTS_SUCCESS;
+}
+
+int cts_vcard_make(const CTSstruct *contact, char **vcard_stream, int flags)
+{
+       int ret_len, ret;
+       char result[CTS_VCARD_FILE_MAX_SIZE];
+
+       retv_if(NULL == contact, CTS_ERR_ARG_NULL);
+       retv_if(NULL == vcard_stream, CTS_ERR_ARG_NULL);
+       retvm_if(CTS_STRUCT_CONTACT != contact->s_type, CTS_ERR_ARG_INVALID,
+                       "The record(%d) must be type of CTS_STRUCT_CONTACT.", contact->s_type);
+
+       cts_vcard_initial();
+
+       ret_len = snprintf(result, sizeof(result), "%s%s", "BEGIN:VCARD", CTS_CRLF);
+       ret_len += snprintf(result+ret_len, sizeof(result)-ret_len,
+                       "%s%s%s", "VERSION:", "3.0", CTS_CRLF);
+
+       ret_len += cts_vcard_append_contact(flags, (contact_t *)contact,
+                       result+ret_len, sizeof(result)-ret_len);
+
+       retvm_if(sizeof(result)-ret_len <= 0, CTS_ERR_EXCEEDED_LIMIT,
+                       "This contact has too many information");
+
+       ret_len += snprintf(result+ret_len, sizeof(result)-ret_len,
+                       "%s%s", "END:VCARD", CTS_CRLF);
+
+       ret = cts_vcard_add_folding(result);
+       if (CTS_SUCCESS != ret)
+               return ret;
+       *vcard_stream = strdup(result);
+
+       return CTS_SUCCESS;
+}
+
diff --git a/src/cts-vcard-file.h b/src/cts-vcard-file.h
new file mode 100755 (executable)
index 0000000..a82d6be
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_VCARD_FILE_H__
+#define __CTS_VCARD_FILE_H__
+
+#define CTS_VCARD_FILE_MAX_SIZE 1024*1024
+#define CTS_VCARD_PHOTO_MAX_SIZE 1024*100
+
+int cts_vcard_parse(const void *vcard_stream, CTSstruct **contact, int flags);
+int cts_vcard_make(const CTSstruct *contact, char **vcard_stream, int flags);
+
+#endif //__CTS_VCARD_FILE_H__
+
+
diff --git a/src/cts-vcard.c b/src/cts-vcard.c
new file mode 100755 (executable)
index 0000000..8f02dfc
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <errno.h>
+
+#include "cts-internal.h"
+#include "cts-types.h"
+#include "cts-contact.h"
+#include "cts-vcard.h"
+#include "cts-utils.h"
+#include "cts-sqlite.h"
+#include "cts-vcard-file.h"
+#include "cts-struct-ext.h"
+
+API int contacts_svc_get_vcard_from_contact(
+               const CTSstruct *contact, char **vcard_stream)
+{
+       return cts_vcard_make(contact, vcard_stream, CTS_VCARD_CONTENT_BASIC);
+}
+
+API int contacts_svc_get_contact_from_vcard(
+               const char *vcard_stream, CTSstruct **contact)
+{
+       int ret;
+
+       ret = cts_vcard_parse(vcard_stream, contact, CTS_VCARD_CONTENT_BASIC);
+       retvm_if(ret, ret, "cts_vcard_parse() Failed(%d)", ret);
+
+       return CTS_SUCCESS;
+}
+
+static inline void cts_remove_name(cts_name *name)
+{
+       name->is_changed = true;
+       if (name->first) {
+               free(name->first);
+               name->first = NULL;
+       }
+       if (name->last) {
+               free(name->last);
+               name->last = NULL;
+       }
+       if (name->addition) {
+               free(name->addition);
+               name->addition = NULL;
+       }
+       if (name->display) {
+               free(name->display);
+               name->display = NULL;
+       }
+       if (name->prefix) {
+               free(name->prefix);
+               name->prefix = NULL;
+       }
+       if (name->suffix) {
+               free(name->suffix);
+               name->suffix = NULL;
+       }
+}
+
+static inline void cts_remove_company(cts_company *company)
+{
+       if (company->name) {
+               free(company->name);
+               company->name = NULL;
+       }
+       if (company->department) {
+               free(company->department);
+               company->department = NULL;
+       }
+       if (company->jot_title) {
+               free(company->jot_title);
+               company->jot_title = NULL;
+       }
+       if (company->role) {
+               free(company->role);
+               company->role = NULL;
+       }
+}
+
+static inline void cts_remove_base(cts_ct_base *base)
+{
+       if (base->img_path) {
+               free(base->img_path);
+               base->img_path = NULL;
+               base->img_changed = true;
+       }
+       if (base->full_img_path) {
+               free(base->full_img_path);
+               base->full_img_path = NULL;
+               base->full_img_changed = true;
+       }
+       if (base->note) {
+               free(base->note);
+               base->note = NULL;
+               base->note_changed = true;
+       }
+}
+
+static void cts_remove_number(gpointer data, gpointer user_data)
+{
+       ((cts_number*)data)->deleted = true;
+}
+
+void cts_remove_email(gpointer data, gpointer user_data)
+{
+       ((cts_email*)data)->deleted = true;
+}
+
+void cts_remove_event(gpointer data, gpointer user_data)
+{
+       ((cts_event*)data)->deleted = true;
+}
+
+void cts_remove_postal(gpointer data, gpointer user_data)
+{
+       ((cts_postal*)data)->deleted = true;
+}
+
+void cts_remove_web(gpointer data, gpointer user_data)
+{
+       ((cts_web*)data)->deleted = true;
+}
+
+void cts_remove_nick(gpointer data, gpointer user_data)
+{
+       ((cts_nickname*)data)->deleted = true;
+}
+
+void cts_remove_grouprel(gpointer data, gpointer user_data)
+{
+       ((cts_group*)data)->deleted = true;
+}
+
+/*
+       void cts_remove_extend(gpointer data, gpointer user_data)
+       {
+       cts_extend *extend = data;
+       if(0000 == extend->type) extend->deleted = true;
+       }
+       */
+
+static inline void cts_contact_remove_vcard_field(contact_t *contact, int flags)
+{
+       if (contact->name)
+               cts_remove_name(contact->name);
+       if (contact->company)
+               cts_remove_company(contact->company);
+       if (contact->base)
+               cts_remove_base(contact->base);
+
+       g_slist_foreach(contact->numbers, cts_remove_number, NULL);
+       g_slist_foreach(contact->emails, cts_remove_email, NULL);
+       g_slist_foreach(contact->events, cts_remove_event, NULL);
+       g_slist_foreach(contact->postal_addrs, cts_remove_postal, NULL);
+       g_slist_foreach(contact->web_addrs, cts_remove_web, NULL);
+       g_slist_foreach(contact->nicknames, cts_remove_nick, NULL);
+       if (flags & CTS_VCARD_CONTENT_X_SLP_GROUP)
+               g_slist_foreach(contact->grouprelations, cts_remove_grouprel, NULL);
+       //g_slist_foreach(contact->extended_values, cts_remove_extend, NULL);
+}
+
+API int contacts_svc_insert_vcard(int addressbook_id, const char* a_vcard_stream)
+{
+       int ret;
+       CTSstruct *vcard_ct;
+
+       retv_if(NULL == a_vcard_stream, CTS_ERR_ARG_NULL);
+
+       ret = cts_vcard_parse(a_vcard_stream, &vcard_ct, CTS_VCARD_CONTENT_BASIC);
+       retvm_if(CTS_SUCCESS != ret, ret, "cts_vcard_parse() Failed(%d)", ret);
+
+       ret = contacts_svc_insert_contact(addressbook_id, vcard_ct);
+       warn_if(ret < CTS_SUCCESS, "contacts_svc_insert_contact() Failed(%d)", ret);
+
+       contacts_svc_struct_free(vcard_ct);
+
+       return ret;
+}
+
+API int contacts_svc_replace_by_vcard(int contact_id, const char* a_vcard_stream)
+{
+       int ret;
+       CTSstruct *vcard_ct, *contact=NULL;
+
+       retv_if(NULL == a_vcard_stream, CTS_ERR_ARG_NULL);
+
+       ret = contacts_svc_get_contact(contact_id, &contact);
+       retvm_if(CTS_SUCCESS != ret, ret, "contacts_svc_get_contact() Failed(%d)", ret);
+
+       ret = cts_vcard_parse(a_vcard_stream, &vcard_ct, CTS_VCARD_CONTENT_BASIC);
+       if (CTS_SUCCESS != ret) {
+               if (contact) contacts_svc_struct_free(contact);
+               ERR("cts_vcard_parse() Failed(%d)", ret);
+               return ret;
+       }
+
+       cts_contact_remove_vcard_field((contact_t *)contact, CTS_VCARD_CONTENT_BASIC);
+       ret = contacts_svc_struct_merge(contact, vcard_ct);
+       if (CTS_SUCCESS == ret) {
+               ret = contacts_svc_update_contact(contact);
+               warn_if(CTS_SUCCESS != ret, "contacts_svc_update_contact() Failed(%d)", ret);
+       } else {
+               ERR("contacts_svc_struct_merge() Failed(%d)", ret);
+       }
+
+       contacts_svc_struct_free(contact);
+       contacts_svc_struct_free(vcard_ct);
+
+       return ret;
+}
+
+#define CTS_VCARD_MAX_SIZE 1024*1024
+
+API int contacts_svc_vcard_foreach(const char *vcard_file_name,
+               int (*fn)(const char *a_vcard_stream, void *data), void *data)
+{
+       FILE *file;
+       int buf_size, len;
+       char *stream;
+       char line[1024];
+
+       retv_if(NULL == vcard_file_name, CTS_ERR_ARG_NULL);
+       retv_if(NULL == fn, CTS_ERR_ARG_NULL);
+
+       file = fopen(vcard_file_name, "r");
+       retvm_if(NULL == file, CTS_ERR_FAIL, "fopen() Failed(%d)", errno);
+
+       len = 0;
+       buf_size = CTS_VCARD_MAX_SIZE;
+       stream = malloc(CTS_VCARD_MAX_SIZE);
+       retvm_if(NULL == stream, CTS_ERR_OUT_OF_MEMORY, "malloc() Failed");
+
+       while (fgets(line, sizeof(line), file)) {
+               if (0 == len)
+                       if (strncmp(line, "BEGIN:VCARD", sizeof("BEGIN:VCARD")-1))
+                               continue;
+
+               if (len + sizeof(line) < buf_size)
+                       len += snprintf(stream + len, buf_size - len, "%s", line);
+               else {
+                       char *new_stream;
+                       buf_size += sizeof(line) * 2;
+                       new_stream = realloc(stream, buf_size);
+                       if (new_stream)
+                               stream = new_stream;
+                       else {
+                               free(stream);
+                               fclose(file);
+                               return CTS_ERR_OUT_OF_MEMORY;
+                       }
+
+                       len += snprintf(stream + len, buf_size - len, "%s", line);
+               }
+
+               if (0 == strncmp(line, "END:VCARD", 9)) {
+                       if (fn)
+                               if (fn(stream, data)) {
+                                       free(stream);
+                                       fclose(file);
+                                       return CTS_ERR_FINISH_ITER;
+                               }
+                       len = 0;
+               }
+       }
+
+       free(stream);
+       fclose(file);
+       return CTS_SUCCESS;
+}
+
+API int contacts_svc_vcard_count(const char *vcard_file_name)
+{
+       FILE *file;
+       int cnt;
+       char line[1024];
+
+       retv_if(NULL == vcard_file_name, CTS_ERR_ARG_NULL);
+
+       file = fopen(vcard_file_name, "r");
+       retvm_if(NULL == file, CTS_ERR_FAIL, "fopen() Failed(%d)", errno);
+
+       cnt = 0;
+       while (fgets(line, sizeof(line), file)) {
+               if (0 == strncmp(line, "END:VCARD", 9))
+                       cnt++;
+       }
+       fclose(file);
+
+       return cnt;
+}
+
+static inline char* cts_new_strcpy(char *dest, const char *src, int size)
+{
+       int i;
+       for (i=0;i < size && src[i];i++)
+               dest[i] = src[i];
+       dest[i] = '\0';
+
+       return &dest[i];
+}
+
+API char* contacts_svc_vcard_put_content(const char *vcard_stream,
+               const char *content_type, const char *content_value)
+{
+       int i, org_len, new_len;
+       char *new_stream, *cur;
+       const char *end_content = "END:VCARD";
+
+       retvm_if(NULL == vcard_stream, NULL, "vcard_stream is NULL");
+       retvm_if(NULL == content_type, NULL, "content_type is NULL");
+       retvm_if(NULL == content_value, NULL, "content_value is NULL");
+
+       org_len = strlen(vcard_stream);
+       new_len = org_len + strlen(content_type) + strlen(content_value) + 8;
+
+       new_stream = malloc(new_len);
+       retvm_if(NULL == new_stream, NULL, "malloc() Failed");
+
+       memcpy(new_stream, vcard_stream, org_len);
+
+       i = 1;
+       for (cur = new_stream + new_len - 1 ;cur;cur--) {
+               if (end_content[9-i] == *cur) {
+                       if (9 == i) break;
+                       i++;
+                       continue;
+               } else {
+                       i = 1;
+               }
+       }
+       if (9 != i) {
+               ERR("vcard_stream is invalid(%s)", vcard_stream);
+               free(new_stream);
+               return NULL;
+       }
+
+       cur += snprintf(cur, new_len - (cur - new_stream), "%s:", content_type);
+       cur = cts_new_strcpy(cur, content_value, new_len - (cur - new_stream));
+       snprintf(cur, new_len - (cur - new_stream), "\r\n%s\r\n", end_content);
+
+       return new_stream;
+}
+
+API int contacts_svc_vcard_get_content(const char *vcard_stream,
+               const char *content_type, int (*fn)(const char *content_value, void *data), void *data)
+{
+       int len, buf_size, type_len;
+       char *cursor, *found, *value;
+
+       retv_if(NULL == vcard_stream, CTS_ERR_ARG_NULL);
+       retv_if(NULL == content_type, CTS_ERR_ARG_NULL);
+       retv_if(NULL == fn, CTS_ERR_ARG_NULL);
+
+       type_len = strlen(content_type);
+       value = malloc(1024);
+       retvm_if(NULL == value, CTS_ERR_OUT_OF_MEMORY, "malloc() Failed");
+       buf_size = 1024;
+
+       while ((found = strstr(vcard_stream, content_type))) {
+               if ((found != vcard_stream && '\n' != *(found-1))
+                               && ':' != *(found+type_len+1))
+                       continue;
+
+               cursor = found;
+               while (*cursor) {
+                       if ('\r' == *cursor) cursor++;
+                       if ('\n' == *cursor) {
+                               if (' ' != *(cursor+1))
+                                       break;
+                       }
+
+                       cursor++;
+               }
+               len = cursor - found;
+               if (len < buf_size)
+                       memcpy(value, found, len);
+               else {
+                       value = realloc(value, len + 1);
+                       if (value) {
+                               buf_size = len + 1;
+                               memcpy(value, found, len);
+                       }else {
+                               vcard_stream = found + type_len;
+                               continue;
+                       }
+               }
+               value[len] = '\0';
+               if (fn)
+                       if (fn(value+type_len+1, data)) {
+                               free(value);
+                               return CTS_ERR_FINISH_ITER;
+                       }
+               vcard_stream = found + type_len;
+       }
+
+       free(value);
+       return CTS_SUCCESS;
+}
diff --git a/src/cts-vcard.h b/src/cts-vcard.h
new file mode 100755 (executable)
index 0000000..1f73b42
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __CTS_VCARD_H__
+#define __CTS_VCARD_H__
+
+enum{
+       CTS_VCARD_IMG_NONE,
+       CTS_VCARD_IMG_JPEG,
+       CTS_VCARD_IMG_PNG,
+       CTS_VCARD_IMG_GIF,
+       CTS_VCARD_IMG_TIFF,
+};
+
+/**
+ * content type
+ */
+enum VCARDCONTENT {
+       CTS_VCARD_CONTENT_NONE = 0,
+       CTS_VCARD_CONTENT_BASIC = 1<<0,
+       CTS_VCARD_CONTENT_X_SLP_GROUP = 1<<1,
+       CTS_VCARD_CONTENT_ALL = 1<<0|1<<1,
+};
+
+//<!--
+/**
+ * This function makes contact record by using vcard file stream.
+ *
+ * @param[in] vcard_stream start point of the stream of vcard.
+ * @param[out] contact Points of the contact record which is returned
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_get_contact_from_vcard(const char *vcard_stream, CTSstruct **contact);
+
+/**
+ * This function makes vcard file stream by using contact record.
+ *
+ * @param[in] contact A contact information
+ * @param[out] vcard_stream start point of the stream of vcard.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_get_vcard_from_contact(const CTSstruct *contact, char **vcard_stream);
+
+/**
+ * This function inserts a contact made from vcard file stream.
+ *
+ * @param[in] addressbook_id The index of addressbook. 0 is local(phone internal)
+ * @param[in] a_vcard_stream start point of the stream of vcard.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_insert_vcard(int addressbook_id, const char* a_vcard_stream);
+
+/**
+ * This function replaces a saved contact made from vcard file stream.
+ * \n If index(ex. LUID) exist, it is invalid. Always contact_id is valid and processed.
+ * If the contact related with contact_id is not existed, return error.
+ *
+ * @param[in] contact_id The related index of contact.
+ * @param[in] a_vcard_stream start point of the stream of vcard.
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_replace_by_vcard(int contact_id, const char* a_vcard_stream);
+
+/**
+ * This function calls handling function for each vcard of vcard file.
+ *
+ * @param[in] vcard_file_name the name of vcard file
+ * @param[in] fn function pointer for handling each vcard stream.
+ *               If this function doesn't return #CTS_SUCCESS, this function is terminated.
+ * @param[in] data data which is passed to callback function
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_vcard_foreach(const char *vcard_file_name,
+               int (*fn)(const char *a_vcard_stream, void *data), void *data);
+
+/**
+ * This function gets count of vcard in the file.
+ *
+ * @param[in] vcard_file_name the name of vcard file
+ * @return The count number on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_vcard_count(const char *vcard_file_name);
+
+/**
+ * This function puts vcard content.
+ * If vcard stream has vcards, this function puts new content into the last vcard.
+ * you should free new vcard stream after using.
+ * \n This should be used for extended type("X-").
+ *
+ * @param[in] vcard_stream start point of the stream of vcard.
+ * @param[in] content_type The type of vcard content
+ * @param[in] content_value The value of vcard content
+ * @return new vcard stream on success, NULL on error
+ */
+char* contacts_svc_vcard_put_content(const char *vcard_stream,
+               const char *content_type, const char *content_value);
+
+/**
+ * This function gets values of vcard content.
+ * The each value will be passed to fn function.
+ * \n This should be used for extended type("X-").
+ *
+ * @param[in] vcard_stream start point of the stream of vcard.
+ * @param[in] content_type The type of vcard content
+ * @param[in] fn function pointer for handling each content_value.
+ *               If this function doesn't return #CTS_SUCCESS, this function is terminated.
+ * @param[in] data data which is passed to callback function
+ * @return #CTS_SUCCESS on success, Negative value(#cts_error) on error
+ */
+int contacts_svc_vcard_get_content(const char *vcard_stream,
+               const char *content_type, int (*fn)(const char *content_value, void *data), void *data);
+
+//-->
+
+#endif //__CTS_VCARD_H__
+
diff --git a/test/Makefile b/test/Makefile
new file mode 100755 (executable)
index 0000000..12deb30
--- /dev/null
@@ -0,0 +1,30 @@
+CC = gcc
+
+REQUIRED_PKG = contacts-service
+CFLAGS = -g -Wall
+LDFLAGS = # -L../ -lefence -pthread
+ifdef REQUIRED_PKG
+       CFLAGS += `pkg-config --cflags $(REQUIRED_PKG)`
+       LDFLAGS += `pkg-config --libs $(REQUIRED_PKG)`
+endif
+
+SRCS = contact-test.c phonelog-test.c change-noti-test.c group-test.c vcard2contact-test.c SIMimport-test.c addressbook-test.c
+TIMESRC = timetest.c
+OBJECTS = $(SRCS:.c=.o)
+TIMEOBJ = $(TIMESRC:.c=.o)
+TARGETS = $(OBJECTS:.o=)
+#A:.c=.o  //A안에 있는 .c를 .o로 바꿔라
+
+
+all: $(OBJECTS) $(TARGETS)
+#-mv test1 testlocal /usr/
+
+$(TARGETS): $(TIMEOBJ)
+$(TIMEOBJ): timetest.h
+
+% : %.o
+       $(CC) -o $@ $< $(TIMEOBJ) $(LDFLAGS)
+
+clean:
+       rm -rf $(OBJECTS) $(TARGETS) $(TIMEOBJ)
+
diff --git a/test/SIMimport-test.c b/test/SIMimport-test.c
new file mode 100755 (executable)
index 0000000..1cbc357
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <stdio.h>
+#include <contacts-svc.h>
+
+int main()
+{
+       contacts_svc_connect();
+
+       int ret = contacts_svc_import_sim();
+       printf("contacts_svc_import_sim() return %d\n", ret);
+
+       contacts_svc_disconnect();
+       return 0;
+}
+
+
diff --git a/test/addressbook-test.c b/test/addressbook-test.c
new file mode 100755 (executable)
index 0000000..32ba2d9
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <stdio.h>
+
+#include <contacts-svc.h>
+
+int insert_addrbook(int acc_id, int acc_type, int mode, const char *group_name)
+{
+       int ret;
+       CTSvalue *ab;
+       ab = contacts_svc_value_new(CTS_VALUE_ADDRESSBOOK);
+
+       contacts_svc_value_set_int(ab, CTS_ADDRESSBOOK_VAL_ACC_ID_INT, acc_id);
+       contacts_svc_value_set_int(ab, CTS_ADDRESSBOOK_VAL_ACC_TYPE_INT, acc_type);
+       contacts_svc_value_set_int(ab, CTS_ADDRESSBOOK_VAL_MODE_INT, mode);
+       contacts_svc_value_set_str(ab, CTS_ADDRESSBOOK_VAL_NAME_STR, group_name);
+
+       ret = contacts_svc_insert_addressbook(ab);
+       if (ret < CTS_SUCCESS)
+               printf("contacts_svc_insert_addressbook() Failed\n");
+
+       contacts_svc_value_free(ab);
+       return ret;
+}
+
+void get_addrbook(int addressbook_id)
+{
+       int ret;
+       const char *name;
+       CTSvalue *ab = NULL;
+
+       ret = contacts_svc_get_addressbook(addressbook_id, &ab);
+       if (CTS_SUCCESS != ret) {
+               printf("contacts_svc_get_addressbook() Failed\n");
+               return;
+       }
+
+       printf("///////////%d//////////////\n",
+                       contacts_svc_value_get_int(ab, CTS_ADDRESSBOOK_VAL_ID_INT));
+       printf("The related account ID : %d\n",
+                       contacts_svc_value_get_int(ab, CTS_ADDRESSBOOK_VAL_ACC_ID_INT));
+       printf("The related account type : %d\n",
+                       contacts_svc_value_get_int(ab, CTS_ADDRESSBOOK_VAL_ACC_TYPE_INT));
+       printf("permission : %d\n",
+                       contacts_svc_value_get_int(ab, CTS_ADDRESSBOOK_VAL_MODE_INT));
+
+       name = contacts_svc_value_get_str(ab, CTS_ADDRESSBOOK_VAL_NAME_STR);
+       if (name)
+               printf("Name : %s\n", name);
+       printf("//////////////////////////\n");
+
+       contacts_svc_value_free(ab);
+}
+
+void update_addrbook(void)
+{
+       int ret;
+       CTSvalue *ab = NULL;
+       ret = contacts_svc_get_addressbook(2, &ab);
+       if (CTS_SUCCESS != ret) {
+               printf("contacts_svc_get_addressbook() Failed\n");
+               return;
+       }
+
+       contacts_svc_value_set_str(ab, CTS_ADDRESSBOOK_VAL_NAME_STR,"Fixed-addressbook");
+
+       ret = contacts_svc_update_addressbook(ab);
+       if (ret < CTS_SUCCESS)
+               printf("contacts_svc_update_addressbook() Failed\n");
+
+       contacts_svc_value_free(ab);
+}
+
+void delete_addrbook(int addressbook_id)
+{
+       int ret;
+       ret = contacts_svc_delete_addressbook(addressbook_id);
+       if (CTS_SUCCESS != ret)
+               printf("Error : contacts_svc_delete_addressbook() Failed(%d)\n", ret);
+}
+
+static int list_cb(CTSvalue *ab, void *user_data)
+{
+       const char *name;
+
+       printf("///////////%d//////////////\n",
+                       contacts_svc_value_get_int(ab, CTS_LIST_ADDRESSBOOK_ID_INT));
+       printf("The related account ID : %d\n",
+                       contacts_svc_value_get_int(ab, CTS_LIST_ADDRESSBOOK_ACC_ID_INT));
+       printf("The related account type : %d\n",
+                       contacts_svc_value_get_int(ab, CTS_LIST_ADDRESSBOOK_ACC_TYPE_INT));
+       printf("permission : %d\n",
+                       contacts_svc_value_get_int(ab, CTS_LIST_ADDRESSBOOK_MODE_INT));
+
+       name = contacts_svc_value_get_str(ab, CTS_LIST_ADDRESSBOOK_NAME_STR);
+       if (name)
+               printf("Name : %s\n", name);
+       printf("//////////////////////////\n");
+
+       return CTS_SUCCESS;
+}
+
+void addrbook_list(void)
+{
+       int ret;
+
+       printf("///////////0//////////////\n");
+       printf("Name : %s\n", "Internal Addressbook(This is logical value)");
+       printf("//////////////////////////\n");
+
+       ret = contacts_svc_list_foreach(CTS_LIST_ALL_ADDRESSBOOK, list_cb, NULL);
+       if (CTS_SUCCESS != ret) {
+               printf("contacts_svc_list_foreach() Failed\n");
+               return;
+       }
+}
+
+void addrbook_list2(void)
+{
+       int ret, count;
+       CTSiter *iter;
+
+       count = contacts_svc_count_with_int(CTS_GET_COUNT_CONTACTS_IN_ADDRESSBOOK, 0);
+       printf("Phone(%d)", count);
+
+       ret = contacts_svc_get_list(CTS_LIST_ALL_ADDRESSBOOK, &iter);
+       if (CTS_SUCCESS != ret) {
+               printf("contacts_svc_get_list() Failed(%d)\n", ret);
+               return;
+       }
+
+       while (CTS_SUCCESS == contacts_svc_iter_next(iter)) {
+               int id;
+               const char *name;
+               CTSvalue *info;
+
+               info = contacts_svc_iter_get_info(iter);
+               id = contacts_svc_value_get_int(info, CTS_LIST_ADDRESSBOOK_ID_INT);
+               name = contacts_svc_value_get_str(info, CTS_LIST_ADDRESSBOOK_NAME_STR);
+               count = contacts_svc_count_with_int(CTS_GET_COUNT_CONTACTS_IN_ADDRESSBOOK, id);
+
+               printf("%s(%d)", name, count);
+       }
+       contacts_svc_iter_remove(iter);
+}
+
+int main()
+{
+       int id;
+       contacts_svc_connect();
+       insert_addrbook(1, CTS_ADDRESSBOOK_TYPE_GOOGLE, CTS_ADDRESSBOOK_MODE_NONE, "test1");
+       insert_addrbook(1, CTS_ADDRESSBOOK_TYPE_GOOGLE, CTS_ADDRESSBOOK_MODE_NONE, "test2");
+       id = insert_addrbook(2, CTS_ADDRESSBOOK_TYPE_FACEBOOK, CTS_ADDRESSBOOK_MODE_READONLY,
+                       "facebook-test");
+       get_addrbook(id);
+       addrbook_list();
+       update_addrbook();
+       addrbook_list();
+       delete_addrbook(id);
+       addrbook_list();
+       addrbook_list2();
+
+       contacts_svc_disconnect();
+       return 0;
+}
+
+
+
diff --git a/test/change-noti-test.c b/test/change-noti-test.c
new file mode 100755 (executable)
index 0000000..754b0b7
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <stdio.h>
+#include <glib.h>
+#include <contacts-svc.h>
+
+static void favorite_change_callback(void *data)
+{
+       printf("Favorite data of contacts service is changed\n");
+}
+
+static void plog_change_callback(void *data)
+{
+       printf("Phone log data of contacts service is changed\n");
+}
+
+static void contact_change_callback(void *data)
+{
+       printf("Contact data of contacts service is changed\n");
+}
+
+static void missed_call_change_callback(void *data)
+{
+       printf("Missed Call is changed\n");
+}
+
+int main()
+{
+       GMainLoop *loop;
+
+       contacts_svc_connect();
+       contacts_svc_subscribe_change(CTS_SUBSCRIBE_CONTACT_CHANGE, contact_change_callback, NULL);
+       contacts_svc_subscribe_change(CTS_SUBSCRIBE_PLOG_CHANGE, plog_change_callback, NULL);
+       contacts_svc_subscribe_change(CTS_SUBSCRIBE_FAVORITE_CHANGE, favorite_change_callback, NULL);
+       contacts_svc_subscribe_change(CTS_SUBSCRIBE_MISSED_CALL_CHANGE, missed_call_change_callback, NULL);
+
+       loop = g_main_loop_new(NULL, FALSE);
+       g_main_loop_run(loop);
+
+       contacts_svc_unsubscribe_change(CTS_SUBSCRIBE_CONTACT_CHANGE, contact_change_callback);
+       contacts_svc_unsubscribe_change(CTS_SUBSCRIBE_PLOG_CHANGE, plog_change_callback);
+       contacts_svc_unsubscribe_change(CTS_SUBSCRIBE_FAVORITE_CHANGE, favorite_change_callback);
+       contacts_svc_unsubscribe_change(CTS_SUBSCRIBE_MISSED_CALL_CHANGE, favorite_change_callback);
+
+       contacts_svc_disconnect();
+       g_main_loop_unref(loop);
+
+       return 0;
+}
+
diff --git a/test/contact-test.c b/test/contact-test.c
new file mode 100755 (executable)
index 0000000..037178f
--- /dev/null
@@ -0,0 +1,868 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <contacts-svc.h>
+
+static int insert_test(void)
+{
+       CTSstruct *contact;
+       CTSvalue *name, *number1, *number2;
+       CTSvalue *nick, *event;
+       GSList *numbers, *nicknames, *events;
+       contact = contacts_svc_struct_new(CTS_STRUCT_CONTACT);
+
+       CTSvalue *base = contacts_svc_value_new(CTS_VALUE_CONTACT_BASE_INFO);
+       if (base) {
+               //contacts_svc_value_set_str(base, CTS_BASE_VAL_IMG_PATH_STR, "/opt/media/Images and videos/Wallpapers/Wallpaper3.jpg");
+       }
+       contacts_svc_struct_store_value(contact, CTS_CF_BASE_INFO_VALUE, base);
+       contacts_svc_value_free(base);
+
+       name = contacts_svc_value_new(CTS_VALUE_NAME);
+       if (name) {
+               contacts_svc_value_set_str(name, CTS_NAME_VAL_FIRST_STR, "gildong");
+               contacts_svc_value_set_str(name, CTS_NAME_VAL_LAST_STR, "Hong");
+               contacts_svc_value_set_str(name, CTS_NAME_VAL_SUFFIX_STR, "engineer");
+       }
+       contacts_svc_struct_store_value(contact, CTS_CF_NAME_VALUE, name);
+       contacts_svc_value_free(name);
+
+       numbers = NULL;
+       number1 = contacts_svc_value_new(CTS_VALUE_NUMBER);
+       if (number1) {
+               contacts_svc_value_set_str(number1, CTS_NUM_VAL_NUMBER_STR, "0987654321");
+               contacts_svc_value_set_int(number1, CTS_NUM_VAL_TYPE_INT,
+                               CTS_NUM_TYPE_CELL);
+               contacts_svc_value_set_bool(number1, CTS_NUM_VAL_DEFAULT_BOOL, true);
+       }
+       numbers = g_slist_append(numbers, number1);
+
+       number2 = contacts_svc_value_new(CTS_VALUE_NUMBER);
+       if (number2) {
+               contacts_svc_value_set_str(number2, CTS_NUM_VAL_NUMBER_STR, "0123456789");
+               contacts_svc_value_set_int(number2, CTS_NUM_VAL_TYPE_INT,
+                               CTS_NUM_TYPE_WORK|CTS_NUM_TYPE_VOICE);
+       }
+       numbers = g_slist_append(numbers, number2);
+
+       contacts_svc_struct_store_list(contact, CTS_CF_NUMBER_LIST, numbers);
+       contacts_svc_value_free(number1);
+       contacts_svc_value_free(number2);
+       g_slist_free(numbers);
+
+       nicknames = NULL;
+       nick = contacts_svc_value_new(CTS_VALUE_NICKNAME);
+       if (nick)
+               contacts_svc_value_set_str(nick, CTS_NICKNAME_VAL_NAME_STR, "Samm");
+
+       nicknames = g_slist_append(nicknames, nick);
+       contacts_svc_struct_store_list(contact, CTS_CF_NICKNAME_LIST, nicknames);
+       contacts_svc_value_free(nick);
+       g_slist_free(nicknames);
+
+       nicknames = NULL;
+       contacts_svc_struct_get_list(contact, CTS_CF_NICKNAME_LIST, &nicknames);
+       if (nicknames)
+               nick = contacts_svc_value_new(CTS_VALUE_NICKNAME);
+       if (nick)
+               contacts_svc_value_set_str(nick, CTS_NICKNAME_VAL_NAME_STR, "3star");
+       nicknames = g_slist_append(nicknames, nick);
+       contacts_svc_struct_store_list(contact, CTS_CF_NICKNAME_LIST, nicknames);
+       contacts_svc_value_free(nick);
+       //never free nicknames
+
+       events = NULL;
+       event = contacts_svc_value_new(CTS_VALUE_EVENT);
+       if (event) {
+               contacts_svc_value_set_int(event, CTS_EVENT_VAL_DATE_INT, 20110526);
+               contacts_svc_value_set_int(event, CTS_EVENT_VAL_TYPE_INT, CTS_EVENT_TYPE_BIRTH);
+       }
+
+       events = g_slist_append(events, event);
+       contacts_svc_struct_store_list(contact, CTS_CF_EVENT_LIST, events);
+       contacts_svc_value_free(event);
+       g_slist_free(events);
+
+       int ret = contacts_svc_insert_contact(0, contact);
+       contacts_svc_struct_free(contact);
+
+       return ret;
+}
+
+void delete_test(void)
+{
+       //get contact
+       //CTSstruct *contact;
+       //contacts_svc_struct_get_value(contact, CTS_CF_INDEX_INT, &value);
+       //int index = contacts_svc_value_get_int(value, CTS_BASIC_VAL_INT);
+
+       contacts_svc_delete_contact(2);
+
+       //contacts_svc_struct_free(contact);
+
+#if DELETE_CONTACTS
+       // TODO: get each index of contacts
+       int i, index_list[10] ={1,3,4,65,345,54,5,2,9,10};
+       int ret;
+
+       ret = contacts_svc_begin_trans();
+       if (CTS_SUCCESS != ret) return;
+       for (i=0;i<10;i++) {
+               ret = contacts_svc_delete_contact(index_list[i]);
+               if (CTS_SUCCESS != ret) {
+                       contacts_svc_end_trans(false);
+                       return;
+               }
+       }
+       ret = contacts_svc_end_trans(true);
+       if (ret < CTS_SUCCESS){
+               printf("all work were rollbacked");
+               return;
+       }
+#endif
+
+}
+
+void update_test()
+{
+       int ret;
+       GSList *numbers, *cursor, *groupList, *nicknames;
+       CTSvalue *number=NULL, *name=NULL, *group = NULL, *company, *nick;
+       CTSstruct *contact=NULL;
+
+       ret = contacts_svc_get_contact(1, &contact);
+       if (ret < CTS_SUCCESS) return;
+
+       contacts_svc_struct_get_value(contact, CTS_CF_NAME_VALUE, &name);
+       contacts_svc_value_set_str(name, CTS_NAME_VAL_FIRST_STR, "Changed first");
+       contacts_svc_value_set_str(name, CTS_NAME_VAL_LAST_STR, "Changed last");
+       contacts_svc_value_set_str(name, CTS_NAME_VAL_PREFIX_STR, "Changed prefix");
+       contacts_svc_value_set_str(name, CTS_NAME_VAL_SUFFIX_STR, NULL);
+
+       numbers = NULL;
+       contacts_svc_struct_get_list(contact, CTS_CF_NUMBER_LIST, &numbers);
+       cursor = numbers;
+       if (cursor) {
+               //char *temp = contacts_svc_value_get_str(cursor->data, CTS_NUM_VAL_NUMBER_STR);
+               contacts_svc_value_set_str(cursor->data, CTS_NUM_VAL_NUMBER_STR, "0987651234");
+
+               cursor = g_slist_next(cursor);
+               if (cursor)
+                       contacts_svc_value_set_bool(cursor->data, CTS_NUM_VAL_DELETE_BOOL, true);
+
+               number = contacts_svc_value_new(CTS_VALUE_NUMBER);
+               if (number) {
+                       contacts_svc_value_set_str(number, CTS_NUM_VAL_NUMBER_STR, "+82125439876");
+                       contacts_svc_value_set_int(number, CTS_NUM_VAL_TYPE_INT,
+                                       CTS_NUM_TYPE_WORK|CTS_NUM_TYPE_FAX);
+                       //         contacts_svc_value_set_bool(number, CTS_NUM_VAL_DEFAULT_BOOL, true);
+                       numbers = g_slist_append(numbers, number);
+               }
+       }
+
+       contacts_svc_struct_store_list(contact, CTS_CF_NUMBER_LIST, numbers);
+       contacts_svc_value_free(number);
+       //free("+82125439876");
+
+       groupList = NULL;
+       contacts_svc_struct_get_list(contact, CTS_CF_GROUPREL_LIST, &groupList);
+
+       cursor = groupList;
+       cursor=g_slist_next(groupList);
+       if (cursor)
+               contacts_svc_value_set_bool(cursor->data, CTS_GROUPREL_VAL_DELETE_BOOL, true);
+
+       group = contacts_svc_value_new(CTS_VALUE_GROUP_RELATION);
+       if (group) {
+               contacts_svc_value_set_int(group, CTS_GROUPREL_VAL_ID_INT, 2);
+               groupList = g_slist_append(groupList, group);
+       }
+       contacts_svc_struct_store_list(contact, CTS_CF_GROUPREL_LIST, groupList);
+       contacts_svc_value_free(group);
+
+       company = contacts_svc_value_new(CTS_VALUE_COMPANY);
+       if (company) {
+               contacts_svc_value_set_str(company, CTS_COMPANY_VAL_NAME_STR, "Company");
+               contacts_svc_value_set_str(company, CTS_COMPANY_VAL_DEPARTMENT_STR, "department");
+               contacts_svc_value_set_str(company, CTS_COMPANY_VAL_JOB_TITLE_STR, "engineer");
+       }
+       contacts_svc_struct_store_value(contact, CTS_CF_COMPANY_VALUE, company);
+
+       nicknames = NULL;
+       contacts_svc_struct_get_list(contact, CTS_CF_NICKNAME_LIST, &nicknames);
+       cursor = nicknames;
+       if (cursor) {
+               contacts_svc_value_set_bool(cursor->data, CTS_NICKNAME_VAL_DELETE_BOOL, true);
+
+               nick = contacts_svc_value_new(CTS_VALUE_NICKNAME);
+               if (nick) {
+                       contacts_svc_value_set_str(nick, CTS_NICKNAME_VAL_NAME_STR, "good company");
+                       nicknames = g_slist_append(nicknames, nick);
+               }
+               contacts_svc_struct_store_list(contact, CTS_CF_NICKNAME_LIST, nicknames);
+               contacts_svc_value_free(nick);
+       }
+
+
+       contacts_svc_update_contact(contact);
+       contacts_svc_struct_free(contact);
+}
+
+static void translation_type(int type, char *dest, int dest_size)
+{
+       const char *type_str;
+       if (type & CTS_NUM_TYPE_CUSTOM)
+       {
+               char *custom;
+               custom = contacts_svc_get_custom_type(CTS_TYPE_CLASS_NUM, type);
+               if (NULL == custom)
+                       type_str = "Other";
+               else {
+                       snprintf(dest, dest_size, custom);
+                       free(custom);
+                       return;
+               }
+       }
+       else if (type & CTS_NUM_TYPE_CELL)
+               type_str = "Mobile";
+       else if (type & CTS_NUM_TYPE_VOICE)
+       {
+               if (type & CTS_NUM_TYPE_HOME)
+                       type_str = "Home";
+               else if (type & CTS_NUM_TYPE_WORK)
+                       type_str = "Work";
+               else
+                       type_str = "Telephone";
+       }
+       else if (type & CTS_NUM_TYPE_FAX)
+       {
+               if (type & CTS_NUM_TYPE_HOME)
+                       type_str = "Fax(home)";
+               else if (type & CTS_NUM_TYPE_WORK)
+                       type_str = "Fax(work)";
+               else
+                       type_str = "Fax";
+       }
+       else if (type & CTS_NUM_TYPE_PAGER)
+               type_str = "Pager";
+       else if (type & CTS_NUM_TYPE_CAR)
+               type_str = "Car Telephone";
+       else if (type & CTS_NUM_TYPE_ASSISTANT)
+               type_str = "Assistant";
+       else
+               type_str = "Other";
+
+       snprintf(dest, dest_size, type_str);
+}
+
+void get_contact(CTSstruct *contact)
+{
+       int index=0, ret=-1;
+       CTSvalue *value=NULL;
+       GSList *get_list, *cursor;
+
+       if (!contact) {
+               index = contacts_svc_find_contact_by(CTS_FIND_BY_NUMBER, "125439876");
+               if (index > CTS_SUCCESS)
+                       ret = contacts_svc_get_contact(index, &contact);
+               if (ret < 0)
+               {
+                       printf("No found record\n");
+                       return;
+               }
+       }
+       contacts_svc_struct_get_value(contact, CTS_CF_NAME_VALUE, &value);
+       printf("First Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_FIRST_STR));
+       printf("Last Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_LAST_STR));
+       printf("Additional Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_ADDITION_STR));
+       printf("Display Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_DISPLAY_STR));
+       printf("Prefix Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_PREFIX_STR));
+       printf("Suffix Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_SUFFIX_STR));
+
+       value = NULL;
+       contacts_svc_struct_get_value(contact, CTS_CF_COMPANY_VALUE, &value);
+       printf("Company Name : %s\n", contacts_svc_value_get_str(value, CTS_COMPANY_VAL_NAME_STR));
+       printf("Company Department : %s\n", contacts_svc_value_get_str(value, CTS_COMPANY_VAL_DEPARTMENT_STR));
+
+       get_list = NULL;
+       contacts_svc_struct_get_list(contact, CTS_CF_NUMBER_LIST, &get_list);
+
+       for (cursor=get_list;cursor;cursor=g_slist_next(cursor))
+       {
+               int type;
+               char type_str[100];
+               type = contacts_svc_value_get_int(cursor->data, CTS_NUM_VAL_TYPE_INT);
+               translation_type(type, type_str, sizeof(type_str));
+               printf("number Type = %s  ", type_str);
+
+               if (contacts_svc_value_get_bool(cursor->data, CTS_NUM_VAL_FAVORITE_BOOL))
+                       printf("(favorite)");
+               printf("Number = %s\n",
+                               contacts_svc_value_get_str(cursor->data, CTS_NUM_VAL_NUMBER_STR));
+               if (index)
+                       contacts_svc_set_favorite(CTS_FAVOR_NUMBER,
+                                       contacts_svc_value_get_int(cursor->data, CTS_NUM_VAL_ID_INT));
+       }
+
+       get_list = NULL;
+       contacts_svc_struct_get_list(contact, CTS_CF_EMAIL_LIST, &get_list);
+
+       cursor = get_list;
+       for (;cursor;cursor=g_slist_next(cursor))
+       {
+               printf("email Type = %d",
+                               contacts_svc_value_get_int(cursor->data, CTS_EMAIL_VAL_TYPE_INT));
+
+               printf("email = %s\n",
+                               contacts_svc_value_get_str(cursor->data, CTS_EMAIL_VAL_ADDR_STR));
+       }
+
+       get_list = NULL;
+       contacts_svc_struct_get_list(contact, CTS_CF_GROUPREL_LIST, &get_list);
+       cursor = get_list;
+       for (;cursor;cursor=g_slist_next(cursor))
+       {
+               printf("group = %s:",
+                               contacts_svc_value_get_str(cursor->data, CTS_GROUPREL_VAL_NAME_STR));
+
+               printf("%d\n",
+                               contacts_svc_value_get_int(cursor->data, CTS_GROUPREL_VAL_ID_INT));
+       }
+
+       get_list = NULL;
+       contacts_svc_struct_get_list(contact, CTS_CF_NICKNAME_LIST, &get_list);
+       cursor = get_list;
+       for (;cursor;cursor=g_slist_next(cursor))
+               printf("nickname = %s\n",
+                               contacts_svc_value_get_str(cursor->data, CTS_NICKNAME_VAL_NAME_STR));
+
+
+       if (index)
+               contacts_svc_struct_free(contact);
+
+}
+
+void get_contact_default_num(void)
+{
+       int index, ret;
+       CTSvalue *number=NULL;
+       const char *default_num;
+
+       index = contacts_svc_find_contact_by(CTS_FIND_BY_NUMBER, "0125439876");
+
+       ret = contacts_svc_get_contact_value(CTS_GET_DEFAULT_NUMBER_VALUE, index, &number);
+       if (CTS_SUCCESS != ret) {
+               printf("contacts_svc_get_contact_value() Failed(%d)\n", ret);
+               return;
+       }
+
+       default_num = contacts_svc_value_get_str(number, CTS_NUM_VAL_NUMBER_STR);
+       printf("The default Number is %s\n", default_num);
+       contacts_svc_value_free(number);
+}
+void get_contact_list(void)
+{
+       CTSiter *iter = NULL;
+       printf("Phone contact NUM = %d\n",
+                       contacts_svc_count_with_int(CTS_GET_COUNT_CONTACTS_IN_ADDRESSBOOK, 0));
+
+       contacts_svc_get_list(CTS_LIST_ALL_CONTACT, &iter);
+       //contacts_svc_get_list_with_int(CTS_LIST_MEMBERS_OF_ADDRESSBOOK_ID, 0, &iter);
+
+       while (CTS_SUCCESS == contacts_svc_iter_next(iter))
+       {
+               CTSvalue *contact = NULL;
+               const char *first, *last, *display;
+               contact = contacts_svc_iter_get_info(iter);
+
+               printf("(%8d)", contacts_svc_value_get_int(contact, CTS_LIST_CONTACT_ID_INT));
+               display = contacts_svc_value_get_str(contact, CTS_LIST_CONTACT_DISPLAY_STR);
+               if (display)
+                       printf("%s :", display);
+               else
+               {
+                       first = contacts_svc_value_get_str(contact, CTS_LIST_CONTACT_FIRST_STR);
+                       last = contacts_svc_value_get_str(contact, CTS_LIST_CONTACT_LAST_STR);
+                       if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                               printf("%s %s :", first, last);
+                       else
+                               printf("%s %s :", last, first);
+               }
+               printf("%s", contacts_svc_value_get_str(contact, CTS_LIST_CONTACT_IMG_PATH_STR));
+               printf("\n");
+               contacts_svc_value_free(contact);
+       }
+       contacts_svc_iter_remove(iter);
+}
+
+void sync_data(int ver)
+{
+       int ret, index_num;
+       CTSiter *iter;
+
+       contacts_svc_get_updated_contacts(0, ver, &iter);
+
+       while (CTS_SUCCESS == contacts_svc_iter_next(iter))
+       {
+               CTSstruct *contact= NULL;
+               CTSvalue *row_info = NULL;
+               row_info = contacts_svc_iter_get_info(iter);
+
+               index_num = contacts_svc_value_get_int(row_info, CTS_LIST_CHANGE_ID_INT);
+               printf("(%8d)\n", index_num);
+               int type = contacts_svc_value_get_int(row_info, CTS_LIST_CHANGE_TYPE_INT);
+               int ver = contacts_svc_value_get_int(row_info, CTS_LIST_CHANGE_VER_INT);
+
+               if (CTS_OPERATION_UPDATED == type || CTS_OPERATION_INSERTED == type) {
+                       contacts_svc_get_contact(index_num, &contact);
+                       char *vcard_stream, *new_stream;
+                       char file[128];
+                       snprintf(file, sizeof(file), "test%d.vcf", index_num);
+                       ret = contacts_svc_get_vcard_from_contact(contact, &vcard_stream);
+                       new_stream = contacts_svc_vcard_put_content(vcard_stream, "X-TEST", "1234");
+                       printf("%s\n", (char *)new_stream);
+                       free(new_stream);
+                       if (CTS_SUCCESS == ret) {
+                               //int fd = open(file, O_RDWR | O_CREAT);
+                               //write(fd, (char *)vcard_stream, strlen((char *)vcard_stream));
+                               //close(fd);
+                               CTSstruct *new_contact = NULL;
+                               ret = contacts_svc_get_contact_from_vcard(vcard_stream, &new_contact);
+                               if (CTS_SUCCESS == ret) {
+                                       get_contact(new_contact);
+                                       contacts_svc_struct_free(new_contact);
+                               }
+                               free(vcard_stream);
+                       }
+                       if (CTS_OPERATION_INSERTED == type)
+                               printf("Added : %d \n", ver);
+                       else
+                               printf("Updated : %d \n", ver);
+                       contacts_svc_struct_free(contact);
+               }
+               else
+                       printf("Deleted : %d \n", ver);
+
+               contacts_svc_value_free(row_info);
+       }
+       contacts_svc_iter_remove(iter);
+}
+
+void search_contacts_by_name(void)
+{
+       int ret;
+       CTSiter *iter;
+       ret = contacts_svc_get_list_with_str(CTS_LIST_CONTACTS_WITH_NAME,
+                       "ch", &iter);
+       if (CTS_SUCCESS != ret) return;
+
+       while (CTS_SUCCESS == contacts_svc_iter_next(iter))
+       {
+               CTSvalue *row_info = NULL;
+               const char *first, *last, *display;
+               row_info = contacts_svc_iter_get_info(iter);
+
+               printf("(%8d)", contacts_svc_value_get_int(row_info, CTS_LIST_CONTACT_ID_INT));
+
+               display = contacts_svc_value_get_str(row_info, CTS_LIST_CONTACT_DISPLAY_STR);
+               if (display)
+                       printf("%s :", display);
+               else
+               {
+                       first = contacts_svc_value_get_str(row_info, CTS_LIST_CONTACT_FIRST_STR);
+                       last = contacts_svc_value_get_str(row_info, CTS_LIST_CONTACT_LAST_STR);
+                       if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                               printf("%s %s :", first, last);
+                       else
+                               printf("%s %s :", last, first);
+               }
+               printf("%s", contacts_svc_value_get_str(row_info, CTS_LIST_CONTACT_IMG_PATH_STR));
+               printf("\n");
+               contacts_svc_value_free(row_info);
+       }
+       contacts_svc_iter_remove(iter);
+}
+
+void get_favorite_list(void)
+{
+       CTSiter *iter;
+       contacts_svc_get_list(CTS_LIST_ALL_NUMBER_FAVORITE, &iter);
+
+       while (CTS_SUCCESS == contacts_svc_iter_next(iter)) {
+               CTSvalue *favorite = NULL;
+               const char *first, *last, *display;
+               favorite = contacts_svc_iter_get_info(iter);
+
+               printf("(%8d)", contacts_svc_value_get_int(favorite, CTS_LIST_SHORTCUT_ID_INT));
+               printf(":%d", contacts_svc_value_get_int(favorite, CTS_LIST_SHORTCUT_CONTACT_ID_INT));
+               display = contacts_svc_value_get_str(favorite, CTS_LIST_SHORTCUT_DISPLAY_NAME_STR);
+               if (display)
+                       printf("%s :", display);
+               else
+               {
+                       first = contacts_svc_value_get_str(favorite, CTS_LIST_SHORTCUT_FIRST_NAME_STR);
+                       last = contacts_svc_value_get_str(favorite, CTS_LIST_SHORTCUT_LAST_NAME_STR);
+                       if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                               printf("%s %s :", first, last);
+                       else
+                               printf("%s %s :", last, first);
+               }
+               printf("%s", contacts_svc_value_get_str(favorite, CTS_LIST_SHORTCUT_NUMBER_STR));
+               printf("(%d)", contacts_svc_value_get_int(favorite, CTS_LIST_SHORTCUT_NUMBER_TYPE_INT));
+               printf("-%d)", contacts_svc_value_get_int(favorite, CTS_LIST_SHORTCUT_SPEEDDIAL_INT));
+               printf("%s", contacts_svc_value_get_str(favorite, CTS_LIST_SHORTCUT_IMG_PATH_STR));
+               printf("\n");
+               contacts_svc_value_free(favorite);
+       }
+       contacts_svc_iter_remove(iter);
+}
+
+void put_value_test()
+{
+       CTSvalue *value, *number;
+
+       value = contacts_svc_value_new(CTS_VALUE_CONTACT_BASE_INFO);
+       if (value) {
+               contacts_svc_value_set_str(value, CTS_BASE_VAL_RINGTONE_PATH_STR,
+                               "/opt/test/test.mp3");
+               contacts_svc_put_contact_value(CTS_PUT_VAL_REPLACE_RINGTONE, 1, value);
+               contacts_svc_value_free(value);
+       }
+
+       number = contacts_svc_value_new(CTS_VALUE_NUMBER);
+       if (number) {
+               contacts_svc_value_set_str(number, CTS_NUM_VAL_NUMBER_STR, "0123337777");
+               contacts_svc_value_set_int(number, CTS_NUM_VAL_TYPE_INT, CTS_NUM_TYPE_CELL);
+               //      contacts_svc_value_set_bool(number, CTS_NUM_VAL_DEFAULT_BOOL, true);
+
+               contacts_svc_put_contact_value(CTS_PUT_VAL_ADD_NUMBER, 1, number);
+               contacts_svc_value_free(number);
+       }
+}
+
+static void print_extend_contact(CTSstruct *contact)
+{
+       int ret;
+       CTSvalue *value;
+       GSList *get_list, *cursor;
+       value = NULL;
+       contacts_svc_struct_get_value(contact, CTS_CF_NAME_VALUE, &value);
+       printf("First Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_FIRST_STR));
+       printf("Last Name : %s\n", contacts_svc_value_get_str(value, CTS_NAME_VAL_LAST_STR));
+
+       value = NULL;
+       ret = contacts_svc_find_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "YomiName");
+       ret = contacts_svc_struct_get_value(contact, ret, &value);
+       if (CTS_SUCCESS == ret) {
+               printf("extend1 data2 : %s\n", contacts_svc_value_get_str(value, CTS_EXTEND_VAL_DATA2_STR));
+               printf("extend1 data3 : %s\n", contacts_svc_value_get_str(value, CTS_EXTEND_VAL_DATA3_STR));
+               printf("extend1 data4 : %s\n", contacts_svc_value_get_str(value, CTS_EXTEND_VAL_DATA4_STR));
+       }
+       value = NULL;
+       ret = contacts_svc_find_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "Family");
+       ret = contacts_svc_struct_get_value(contact, ret, &value);
+       if (CTS_SUCCESS == ret) {
+               printf("extend2 data2 : %s\n", contacts_svc_value_get_str(value, CTS_EXTEND_VAL_DATA2_STR));
+               printf("extend2 data3 : %s\n", contacts_svc_value_get_str(value, CTS_EXTEND_VAL_DATA3_STR));
+               printf("extend2 data4 : %s\n", contacts_svc_value_get_str(value, CTS_EXTEND_VAL_DATA4_STR));
+       }
+       get_list = NULL;
+       contacts_svc_struct_get_list(contact, CTS_CF_NUMBER_LIST, &get_list);
+
+       cursor = get_list;
+       for (;cursor;cursor=g_slist_next(cursor))
+       {
+               int type;
+               char type_str[100];
+               type = contacts_svc_value_get_int(cursor->data, CTS_NUM_VAL_TYPE_INT);
+               translation_type(type, type_str, sizeof(type_str));
+               printf("number Type = %s", type_str);
+
+               if (contacts_svc_value_get_bool(cursor->data, CTS_NUM_VAL_FAVORITE_BOOL))
+                       printf("(favorite)");
+               printf("Number = %s\n",
+                               contacts_svc_value_get_str(cursor->data, CTS_NUM_VAL_NUMBER_STR));
+       }
+}
+
+void extend_data_test(void)
+{
+       int ret, index;
+       CTSstruct *contact;
+       CTSvalue *name, *number1, *extend_value;
+       GSList *numbers=NULL;
+
+       contact = contacts_svc_struct_new(CTS_STRUCT_CONTACT);
+
+       name = contacts_svc_value_new(CTS_VALUE_NAME);
+       if (name) {
+               contacts_svc_value_set_str(name, CTS_NAME_VAL_FIRST_STR, "People");
+               contacts_svc_value_set_str(name, CTS_NAME_VAL_LAST_STR, "Japan");
+       }
+       contacts_svc_struct_store_value(contact, CTS_CF_NAME_VALUE, name);
+       contacts_svc_value_free(name);
+
+       number1 = contacts_svc_value_new(CTS_VALUE_NUMBER);
+       if (number1) {
+               contacts_svc_value_set_str(number1, CTS_NUM_VAL_NUMBER_STR, "0333333333");
+               contacts_svc_value_set_int(number1, CTS_NUM_VAL_TYPE_INT, CTS_NUM_TYPE_CELL);
+               contacts_svc_value_set_bool(number1, CTS_NUM_VAL_DEFAULT_BOOL, true);
+       }
+       numbers = g_slist_append(numbers, number1);
+
+       contacts_svc_struct_store_list(contact, CTS_CF_NUMBER_LIST, numbers);
+       contacts_svc_value_free(number1);
+       g_slist_free(numbers);
+
+       extend_value = contacts_svc_value_new(CTS_VALUE_EXTEND);
+       if (extend_value) {
+               contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA2_STR, "YomiFirstName");
+               contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA3_STR, "YomiLastName");
+               contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA4_STR, "YomiCompanyName");
+       }
+       ret = contacts_svc_find_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "YomiName");
+       if (CTS_ERR_DB_RECORD_NOT_FOUND == ret)
+               ret = contacts_svc_insert_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "YomiName");
+       contacts_svc_struct_store_value(contact, ret, extend_value);
+       contacts_svc_value_free(extend_value);
+
+       extend_value = contacts_svc_value_new(CTS_VALUE_EXTEND);
+       if (extend_value) {
+               contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA2_STR, "Children1");
+               contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA3_STR, "Children2");
+               contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA4_STR, "Children3");
+       }
+       ret = contacts_svc_find_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "Family");
+       if (CTS_ERR_DB_RECORD_NOT_FOUND == ret)
+               ret = contacts_svc_insert_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "Family");
+       contacts_svc_struct_store_value(contact, ret, extend_value);
+       contacts_svc_value_free(extend_value);
+
+       index = contacts_svc_insert_contact(0, contact);
+       contacts_svc_struct_free(contact);
+       contact = NULL;
+
+       ret = contacts_svc_get_contact(index, &contact);
+       if (ret < 0)
+       {
+               printf("No found record\n");
+               return;
+       }
+       print_extend_contact(contact);
+
+       //update test
+
+       extend_value = NULL;
+       int type = contacts_svc_find_custom_type(CTS_TYPE_CLASS_EXTEND_DATA, "Family");
+       ret = contacts_svc_struct_get_value(contact, type, &extend_value);
+       if (CTS_SUCCESS == ret)
+               contacts_svc_value_set_str(extend_value, CTS_EXTEND_VAL_DATA2_STR, "Children4");
+       contacts_svc_struct_store_value(contact, type, extend_value);
+
+       contacts_svc_update_contact(contact);
+       contacts_svc_struct_free(contact);
+       contact = NULL;
+
+       ret = contacts_svc_get_contact(index, &contact);
+       if (ret < 0)
+       {
+               printf("No found record\n");
+               return;
+       }
+       print_extend_contact(contact);
+       contacts_svc_struct_free(contact);
+}
+
+void get_number_list(void)
+{
+       CTSiter *iter;
+       contacts_svc_get_list_with_str(CTS_LIST_NUMBERINFOS_WITH_NUM, "123", &iter);
+       //contacts_svc_get_list_with_str(CTS_LIST_NUMBERINFOS_WITH_NAME, "kim", &iter);
+
+       while (CTS_SUCCESS == contacts_svc_iter_next(iter))
+       {
+               CTSvalue *contact = NULL;
+               const char *first, *last, *display;
+               contact = contacts_svc_iter_get_info(iter);
+
+               printf("(%8d)", contacts_svc_value_get_int(contact, CTS_LIST_NUM_CONTACT_ID_INT));
+               display = contacts_svc_value_get_str(contact, CTS_LIST_NUM_CONTACT_DISPLAY_STR);
+               if (display)
+                       printf("%s :", display);
+               else
+               {
+                       first = contacts_svc_value_get_str(contact, CTS_LIST_NUM_CONTACT_FIRST_STR);
+                       last = contacts_svc_value_get_str(contact, CTS_LIST_NUM_CONTACT_LAST_STR);
+                       if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                               printf("%s %s :", first, last);
+                       else
+                               printf("%s %s :", last, first);
+               }
+               printf("%s", contacts_svc_value_get_str(contact, CTS_LIST_NUM_CONTACT_IMG_PATH_STR));
+               printf("\n");
+               printf("%s\n", contacts_svc_value_get_str(contact, CTS_LIST_NUM_NUMBER_STR));
+               contacts_svc_value_free(contact);
+       }
+       contacts_svc_iter_remove(iter);
+}
+
+static int get_search_cb(CTSvalue *value, void *user_data)
+{
+       const char *number, *img_path;
+       const char *first, *last, *display;
+
+       printf("(%8d)", contacts_svc_value_get_int(value, CTS_LIST_NUM_CONTACT_ID_INT));
+       display = contacts_svc_value_get_str(value, CTS_LIST_NUM_CONTACT_DISPLAY_STR);
+       if (display)
+               printf("%s :", display);
+       else
+       {
+               first = contacts_svc_value_get_str(value, CTS_LIST_NUM_CONTACT_FIRST_STR);
+               last = contacts_svc_value_get_str(value, CTS_LIST_NUM_CONTACT_LAST_STR);
+               if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       printf("%s %s :", first, last);
+               else
+                       printf("%s %s :", last, first);
+       }
+
+       img_path = contacts_svc_value_get_str(value, CTS_LIST_NUM_CONTACT_IMG_PATH_STR);
+       if (img_path)
+               printf("%s\n", img_path);
+       else
+               printf("\n");
+
+       number = contacts_svc_value_get_str(value, CTS_LIST_NUM_NUMBER_STR);
+       if (number)
+               printf("%s\n", number);
+
+       return CTS_SUCCESS;
+}
+
+void get_search(void)
+{
+       contacts_svc_smartsearch_excl("fir", 0, 0, get_search_cb, NULL);
+}
+
+static int get_list_with_filter_cb(CTSvalue *value, void *user_data)
+{
+       const char *img_path;
+       const char *first, *last, *display;
+
+       printf("(%8d)", contacts_svc_value_get_int(value, CTS_LIST_CONTACT_ID_INT));
+       display = contacts_svc_value_get_str(value, CTS_LIST_CONTACT_DISPLAY_STR);
+       if (display)
+               printf("%s :", display);
+       else
+       {
+               first = contacts_svc_value_get_str(value, CTS_LIST_CONTACT_FIRST_STR);
+               last = contacts_svc_value_get_str(value, CTS_LIST_CONTACT_LAST_STR);
+               if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                       printf("%s %s :", first, last);
+               else
+                       printf("%s %s :", last, first);
+       }
+
+       img_path = contacts_svc_value_get_str(value, CTS_LIST_CONTACT_IMG_PATH_STR);
+       if (img_path)
+               printf("%s\n", img_path);
+       else
+               printf("\n");
+
+       return CTS_SUCCESS;
+}
+
+void get_list_with_filter(void)
+{
+       int ret;
+       CTSfilter *filter;
+
+       filter = contacts_svc_list_str_filter_new(CTS_FILTERED_CONTACTS_WITH_NAME,
+                       "kim", CTS_LIST_FILTER_ADDRESBOOK_ID_INT, 0, CTS_LIST_FILTER_NONE);
+       if (NULL == filter) {
+               printf("contacts_svc_list_str_filter_new() Failed\n");
+               return;
+       }
+
+       ret = contacts_svc_list_with_filter_foreach(filter, get_list_with_filter_cb, NULL);
+       if (CTS_SUCCESS != ret)
+               printf("contacts_svc_list_with_filter_foreach() Failed(%d)\n", ret);
+
+       contacts_svc_list_filter_free(filter);
+}
+
+int main()
+{
+       int ret, ver;
+       contacts_svc_connect();
+       printf("\n##Insert##\n");
+
+       contacts_svc_begin_trans();
+       ret = insert_test();
+       if (CTS_SUCCESS < ret)
+               ver = contacts_svc_end_trans(true);
+       else
+               contacts_svc_end_trans(false);
+       printf("\n##Insert##\n");
+       insert_test();
+       sleep(2);
+       printf("\n##Update test##\n");
+       update_test();
+       put_value_test();
+       printf("\n##All Contact Information##\n");
+       get_contact(NULL);
+       printf("\n##Default Number##\n");
+       get_contact_default_num();
+
+       printf("\n##Contact List##\n");
+       get_contact_list();
+       printf("\n##Delete Test##\n");
+       delete_test();
+       printf("\n##Sync Test##\n");
+       sync_data(ver);
+
+       printf("\n##Search Name##\n");
+       search_contacts_by_name();
+       printf("\n##Favorite List##\n");
+       get_favorite_list();
+       printf("\n##Favorite 1 Delete##\n");
+       contacts_svc_delete_favorite(1);
+       get_favorite_list();
+
+       printf("\n##Extend Data insert##\n");
+       extend_data_test();
+
+       printf("\n##Number List##\n");
+       get_number_list();
+
+       printf("\n##search##\n");
+       get_search();
+
+       printf("\n##list_with_filter##\n");
+       get_list_with_filter();
+
+       contacts_svc_disconnect();
+
+       return 0;
+}
diff --git a/test/group-test.c b/test/group-test.c
new file mode 100755 (executable)
index 0000000..fb387d5
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <stdio.h>
+#include <glib.h>
+#include <contacts-svc.h>
+
+void insert_group(const char *group_name)
+{
+       int ret;
+       CTSvalue *group;
+       group = contacts_svc_value_new(CTS_VALUE_GROUP);
+
+       contacts_svc_value_set_str(group, CTS_GROUP_VAL_NAME_STR, group_name);
+       contacts_svc_value_set_str(group, CTS_GROUP_VAL_RINGTONE_STR,"/tmp/test.mp3");
+
+       ret = contacts_svc_insert_group(0, group);
+       if (ret < CTS_SUCCESS)
+               printf("contacts_svc_insert_group() Failed\n");
+
+       contacts_svc_value_free(group);
+}
+void get_group(void)
+{
+       int ret;
+       CTSvalue *group = NULL;
+       ret = contacts_svc_get_group(2, &group);
+       if (CTS_SUCCESS != ret) {
+               printf("contacts_svc_get_group() Failed\n");
+               return;
+       }
+
+       printf("Addressbook ID : %d\n",
+                       contacts_svc_value_get_int(group, CTS_GROUP_VAL_ADDRESSBOOK_ID_INT));
+       printf("Name : %s\n",
+                       contacts_svc_value_get_str(group, CTS_GROUP_VAL_NAME_STR));
+       if (contacts_svc_value_get_str(group, CTS_GROUP_VAL_RINGTONE_STR))
+               printf("ringtone : %s\n",
+                               contacts_svc_value_get_str(group, CTS_GROUP_VAL_RINGTONE_STR));
+}
+
+void update_group(void)
+{
+       int ret;
+       CTSvalue *group = NULL;
+       ret = contacts_svc_get_group(2, &group);
+       if (CTS_SUCCESS != ret) {
+               printf("contacts_svc_get_group() Failed\n");
+               return;
+       }
+
+       contacts_svc_value_set_str(group, CTS_GROUP_VAL_NAME_STR,"Fix-Friends");
+       contacts_svc_value_set_str(group, CTS_GROUP_VAL_RINGTONE_STR,"/tmp/change.mp3");
+
+       //free("Fix-Friends");
+       //free("/tmp/change.mp3");
+       ret = contacts_svc_update_group(group);
+       if (ret < CTS_SUCCESS)
+               printf("contacts_svc_update_group() Failed\n");
+
+       contacts_svc_value_free(group);
+}
+
+void delete_group(void)
+{
+       int ret;
+       ret = contacts_svc_delete_group(3);
+       if (CTS_SUCCESS != ret)
+               printf("Error : contacts_svc_delete_group() Failed(%d)\n", ret);
+}
+
+void delete_group_with_members(void)
+{
+       int ret;
+       ret = contacts_svc_delete_group_with_members(1);
+       if (CTS_SUCCESS != ret)
+               printf("Error : contacts_svc_delete_group_with_members() Failed(%d)\n", ret);
+}
+
+void group_list(void)
+{
+       int ret;
+       CTSiter *iter;
+       ret = contacts_svc_get_list(CTS_LIST_ALL_GROUP, &iter);
+       if (CTS_SUCCESS != ret) {
+               printf("contacts_svc_get_list() Failed\n");
+               return;
+       }
+
+       while (CTS_SUCCESS == contacts_svc_iter_next(iter))
+       {
+               CTSvalue *group;
+               const char *name;
+               group = contacts_svc_iter_get_info(iter);
+
+               printf("%8d", contacts_svc_value_get_int(group, CTS_LIST_GROUP_ID_INT));
+               printf("(%d)", contacts_svc_value_get_int(group, CTS_LIST_GROUP_ADDRESSBOOK_ID_INT));
+               name = contacts_svc_value_get_str(group, CTS_LIST_GROUP_NAME_STR);
+               if (name)
+                       printf("%s :", name);
+               printf("\n");
+               contacts_svc_value_free(group);
+       }
+       contacts_svc_iter_remove(iter);
+}
+
+
+int main()
+{
+       contacts_svc_connect();
+       insert_group("Friends");
+       insert_group("Home");
+       get_group();
+       update_group();
+       group_list();
+       delete_group();
+       delete_group_with_members();
+       contacts_svc_disconnect();
+       return 0;
+}
+
diff --git a/test/phonelog-test.c b/test/phonelog-test.c
new file mode 100755 (executable)
index 0000000..38a10f3
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <unistd.h>
+#include <string.h>
+#include <contacts-svc.h>
+
+void phonelog_insert_test(void)
+{
+       CTSvalue *plog;
+
+       plog = contacts_svc_value_new(CTS_VALUE_PHONELOG);
+       contacts_svc_value_set_str(plog, CTS_PLOG_VAL_NUMBER_STR, "0123456789");
+       contacts_svc_value_set_int(plog, CTS_PLOG_VAL_LOG_TIME_INT,(int) time(NULL));
+       contacts_svc_value_set_int(plog, CTS_PLOG_VAL_LOG_TYPE_INT,
+                       CTS_PLOG_TYPE_VOICE_INCOMMING);
+       contacts_svc_value_set_int(plog, CTS_PLOG_VAL_DURATION_INT, 65);
+       contacts_svc_insert_phonelog(plog);
+
+       contacts_svc_value_set_str(plog, CTS_PLOG_VAL_NUMBER_STR, "0987654321");
+       contacts_svc_value_set_int(plog, CTS_PLOG_VAL_LOG_TIME_INT,(int) time(NULL));
+       contacts_svc_value_set_int(plog, CTS_PLOG_VAL_LOG_TYPE_INT,
+                       CTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN);
+       contacts_svc_value_set_int(plog, CTS_PLOG_VAL_DURATION_INT, 65);
+       contacts_svc_insert_phonelog(plog);
+
+       contacts_svc_value_set_str(plog, CTS_PLOG_VAL_NUMBER_STR, "0987654321");
+       contacts_svc_value_set_int(plog, CTS_PLOG_VAL_LOG_TIME_INT,(int) time(NULL));
+       contacts_svc_value_set_int(plog, CTS_PLOG_VAL_LOG_TYPE_INT,
+                       CTS_PLOG_TYPE_VOICE_INCOMMING);
+       contacts_svc_value_set_int(plog, CTS_PLOG_VAL_DURATION_INT, 65);
+       contacts_svc_insert_phonelog(plog);
+
+
+       contacts_svc_value_free(plog);
+}
+void phonelog_modify_test(void)
+{
+       contacts_svc_phonelog_set_seen(2, CTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN);
+
+       contacts_svc_delete_phonelog(CTS_PLOG_DEL_BY_ID, 3);
+       contacts_svc_delete_phonelog(CTS_PLOG_DEL_BY_NUMBER, "0123456789");
+}
+
+void phonelog_get_list_test(void)
+{
+       CTSiter *iter = NULL;
+       char display[1024]={0};
+
+       contacts_svc_get_list(CTS_LIST_GROUPING_PLOG, &iter);
+
+       while (CTS_SUCCESS == contacts_svc_iter_next(iter))
+       {
+               CTSvalue *plog= NULL;
+               plog = contacts_svc_iter_get_info(iter);
+
+               const char *img_path = contacts_svc_value_get_str(plog, CTS_LIST_PLOG_IMG_PATH_STR);
+               const char *display_name = contacts_svc_value_get_str(plog, CTS_LIST_PLOG_DISPLAY_NAME_STR);
+               const char *number = contacts_svc_value_get_str(plog, CTS_LIST_PLOG_NUMBER_STR);
+               if (display_name)
+                       snprintf(display, sizeof(display), "%s", display_name);
+               else
+               {
+                       const char *first = contacts_svc_value_get_str(plog, CTS_LIST_PLOG_FIRST_NAME_STR);
+                       const char *last = contacts_svc_value_get_str(plog, CTS_LIST_PLOG_LAST_NAME_STR);
+                       if (first && last) {
+                               if (CTS_ORDER_NAME_FIRSTLAST == contacts_svc_get_order(CTS_ORDER_OF_DISPLAY))
+                                       snprintf(display, sizeof(display), "%s %s", first, last);
+                               else
+                                       snprintf(display, sizeof(display), "%s %s", last, first);
+                       }else if (first)
+                               strcpy(display, first);
+                       else if (last)
+                               strcpy(display, last);
+                       else {
+                               if (number)
+                                       strcpy(display, number);
+                       }
+               }
+
+               int num_type = contacts_svc_value_get_int(plog, CTS_LIST_PLOG_NUM_TYPE_INT);
+
+               int index = contacts_svc_value_get_int(plog, CTS_LIST_PLOG_ID_INT);
+               int type = contacts_svc_value_get_int(plog, CTS_LIST_PLOG_LOG_TYPE_INT);
+               int time = contacts_svc_value_get_int(plog, CTS_LIST_PLOG_LOG_TIME_INT);
+
+               if (strlen(display))
+                       printf("%d:%s(%s:%d):type=%d:time=%d\n",
+                                       index, display, number, num_type, type, time);
+               if (img_path)
+                       printf("%s\n", img_path);
+               contacts_svc_value_free(plog);
+       }
+       contacts_svc_iter_remove(iter);
+}
+
+void phonelog_get_detail_list_test(void)
+{
+       int ret;
+       CTSiter *iter = NULL;
+       contacts_svc_get_list_with_str(CTS_LIST_PLOGS_OF_NUMBER,"0987654321", &iter);
+
+       ret = contacts_svc_iter_next(iter);
+       while (CTS_SUCCESS == ret)
+       {
+               CTSvalue *plog=NULL;
+               plog = contacts_svc_iter_get_info(iter);
+
+               int index = contacts_svc_value_get_int(plog, CTS_LIST_PLOG_ID_INT);
+               int type = contacts_svc_value_get_int(plog, CTS_LIST_PLOG_LOG_TYPE_INT);
+               int time = contacts_svc_value_get_int(plog, CTS_LIST_PLOG_LOG_TIME_INT);
+               int duration = contacts_svc_value_get_int(plog, CTS_LIST_PLOG_DURATION_INT);
+
+               printf("%d::type=%d:time=%d:duration=%d\n", index, type, time, duration);
+               contacts_svc_value_free(plog);
+               ret = contacts_svc_iter_next(iter);
+       }
+       contacts_svc_iter_remove(iter);
+}
+
+static int plog_get_number_list_cb(const char *number, void *user_data)
+{
+       printf("number = %s\n", number);
+       return CTS_SUCCESS;
+}
+
+void phonelog_get_number_list_test(void)
+{
+       int ret;
+
+       ret = contats_svc_phonelog_get_all_number(plog_get_number_list_cb, NULL);
+       if (CTS_SUCCESS != ret)
+               printf("contats_svc_phonelog_get_all_number() Failed(%d)\n", ret);
+
+}
+
+void phonelog_get_last_call_number_test(void)
+{
+       char *number = contacts_svc_phonelog_get_last_number(CTS_PLOG_LAST_ALL);
+
+       printf("Last Call Number is %s\n", number);
+       free(number);
+}
+
+int main()
+{
+       contacts_svc_connect();
+       phonelog_insert_test();
+       sleep(2);
+       phonelog_insert_test();
+       printf("grouping List 1 <<<<<<<<<<<\n");
+       phonelog_get_list_test();
+       phonelog_modify_test();
+       printf("grouping List 2 <<<<<<<<<<<\n");
+       phonelog_get_list_test();
+       printf("detail List <<<<<<<<<<<\n");
+       phonelog_get_detail_list_test();
+       printf("phonelog number List <<<<<<<<<<<\n");
+       phonelog_get_number_list_test();
+
+       phonelog_get_last_call_number_test();
+
+       contacts_svc_disconnect();
+       return 0;
+}
diff --git a/test/timetest.c b/test/timetest.c
new file mode 100755 (executable)
index 0000000..ac3d3be
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include "timetest.h"
+
+FILE *outfp;
+
+
+double correction;
+
+double set_start_time(void)
+{
+       //      DEBUG_FUNC_START;
+
+       struct timeval tv;
+       double curtime;
+
+       gettimeofday(&tv, NULL);
+       curtime = tv.tv_sec * 1000 + (double)tv.tv_usec/1000;
+       return curtime;
+}
+
+double exec_time(double start)
+{
+       //      DEBUG_FUNC_START;
+
+       double end = set_start_time();
+       return (end - start - correction);
+}
+
+int init_time(void)
+{
+       //      DEBUG_FUNC_START;
+
+       double temp_t;
+       temp_t = set_start_time();
+       correction = exec_time(temp_t);
+
+       return 0;
+}
+
+int print_time(char *prn_args, double time)
+{
+       DEBUG_FUNC_START;
+
+#ifdef USE_STD_OUT
+       printf("%200s =\t", prn_args);
+       printf("%f \n", time);
+#else
+       fprintf(outfp, "%.50s\t", prn_args);
+       fprintf(outfp, "%f \n", time);
+#endif
+
+       return 0;
+}
+
+
+int print_argument(char *prn_args)
+{
+       DEBUG_FUNC_START;
+
+#ifdef USE_STD_OUT
+       printf("%s", prn_args);
+#else
+       fprintf(outfp, "%s\n", prn_args);
+#endif
+
+       return 0;
+}
+
+
+
+int print_milestone(char *prn_args, int level)
+{
+       DEBUG_FUNC_START;
+       int i;
+
+       if (level > 1) {
+               for (i=0;i<level;i++)
+                       printf("\n##################################################################\n");
+               printf("\n%s =\n", prn_args);
+               for (i=0;i<level;i++)
+                       printf("\n##################################################################\n");
+       }
+
+#ifdef USE_STD_OUT
+       if (1 == level)
+               printf("\n##################################################################\n");
+       printf("\n%s =\n", prn_args);
+       printf("\n##################################################################\n");
+#else
+       for (i=0;i<level;i++)
+               fprintf(outfp, "\n##################################################################\n");
+       fprintf(outfp, "%s \n", prn_args);
+       for (i=0;i<level;i++)
+               fprintf(outfp, "\n##################################################################\n");
+#endif
+
+
+       return 0;
+}
+
+int std_output(char *prn_args, double time)
+{
+       DEBUG_FUNC_START;
+
+       printf("%.50s =\t", prn_args);
+       printf("%f \n", time);
+
+       return 0;
+}
+
+
+int file_print_init(char *filename)
+{
+       DEBUG_FUNC_START;
+
+       outfp = fopen(filename, "w"); //"aw"
+       TEST_ERR_PRN_TREAT(NULL == outfp , ("(%s) Open Error \n", filename),
+                       {return -1;});
+       return 0;
+}
+
diff --git a/test/timetest.h b/test/timetest.h
new file mode 100755 (executable)
index 0000000..37b5e05
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef _TIMETEST_H_
+#define _TIMETEST_H_
+
+
+#define TEST_TRACE(fmt, arg...) \
+       printf("[TEST]%s %d:\n" fmt "", __FUNCTION__, __LINE__, ##arg)
+
+#define TEST_DEBUG(fmt, arg...) \
+       printf("\x1b[105;37m[TEST]\x1b[0m(%d)" fmt "", __LINE__, ##arg)
+
+
+#define DEBUG_FUNC_START \
+       printf("\x1b[104;93m[FUNC_START]\x1b[0m%s\n", __FUNCTION__)
+
+
+#define TEST_ERROR_PRINT(fmt, arg...) \
+       printf("\n\x1b[101;38m[ERROR]\x1b[0m%s(%d): " fmt "", __FUNCTION__, __LINE__, ##arg)
+
+#define TEST_ERR_PRN_TREAT(eval, X, expr) if (eval) {TEST_ERROR_PRINT X; expr;} else {;}
+
+
+int init_time(void);
+double set_start_time(void);
+double exec_time(double start);
+
+int print_time(char *prn_args, double time);
+int print_argument(char *prn_args);
+int print_milestone(char *prn_args, int level);
+int std_output(char *prn_args, double time);
+int file_print_init(char *filename);
+
+
+#endif //_TIMETEST_H_
diff --git a/test/vcard2contact-test.c b/test/vcard2contact-test.c
new file mode 100755 (executable)
index 0000000..d3e9e4b
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Contacts Service
+ *
+ * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Youngjae Shin <yj99.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <stdio.h>
+#include <glib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <contacts-svc.h>
+
+#define MAX_BUF 1048576
+
+static void get_contact(CTSstruct *contact)
+{
+       CTSvalue *value;
+       GSList *get_list, *cursor;
+       const char *tmp_str;
+
+       value = NULL;
+       contacts_svc_struct_get_value(contact, CTS_CF_BASE_INFO_VALUE, &value);
+       printf("ID = %d\n", contacts_svc_value_get_int(value, CTS_BASE_VAL_ID_INT));
+       printf("changed time = %d\n", contacts_svc_value_get_int(value, CTS_BASE_VAL_CHANGED_TIME_INT));
+
+       value = NULL;
+       contacts_svc_struct_get_value(contact, CTS_CF_NAME_VALUE, &value);
+       if ((tmp_str = contacts_svc_value_get_str(value, CTS_NAME_VAL_FIRST_STR)))
+               printf("First Name : %s\n", tmp_str);
+       if ((tmp_str = contacts_svc_value_get_str(value, CTS_NAME_VAL_LAST_STR)))
+               printf("Last Name : %s\n", tmp_str);
+       if ((tmp_str = contacts_svc_value_get_str(value, CTS_NAME_VAL_ADDITION_STR)))
+               printf("Additional Name : %s\n", tmp_str);
+       if ((tmp_str = contacts_svc_value_get_str(value, CTS_NAME_VAL_DISPLAY_STR)))
+               printf("Display Name : %s\n", tmp_str);
+       if ((tmp_str = contacts_svc_value_get_str(value, CTS_NAME_VAL_PREFIX_STR)))
+               printf("Prefix Name : %s\n", tmp_str);
+       if ((tmp_str = contacts_svc_value_get_str(value, CTS_NAME_VAL_SUFFIX_STR)))
+               printf("Suffix Name : %s\n", tmp_str);
+
+       value = NULL;
+       contacts_svc_struct_get_value(contact, CTS_CF_COMPANY_VALUE, &value);
+       if ((tmp_str = contacts_svc_value_get_str(value, CTS_COMPANY_VAL_NAME_STR)))
+               printf("Company Name : %s\n", tmp_str);
+       if ((tmp_str = contacts_svc_value_get_str(value, CTS_COMPANY_VAL_DEPARTMENT_STR)))
+               printf("Company Department : %s\n", tmp_str);
+
+       get_list = NULL;
+       contacts_svc_struct_get_list(contact, CTS_CF_NUMBER_LIST, &get_list);
+
+       for (cursor = get_list;cursor;cursor=cursor->next)
+       {
+               printf("number Type = %d",
+                               contacts_svc_value_get_int(cursor->data, CTS_NUM_VAL_TYPE_INT));
+               if (contacts_svc_value_get_bool(cursor->data, CTS_NUM_VAL_FAVORITE_BOOL))
+                       printf("(favorite)");
+               printf("Number = %s\n",
+                               contacts_svc_value_get_str(cursor->data, CTS_NUM_VAL_NUMBER_STR));
+       }
+
+       get_list = NULL;
+       contacts_svc_struct_get_list(contact, CTS_CF_EMAIL_LIST, &get_list);
+
+       for (cursor = get_list;cursor;cursor=cursor->next)
+       {
+               printf("email Type = %d",
+                               contacts_svc_value_get_int(cursor->data, CTS_EMAIL_VAL_TYPE_INT));
+
+               printf("email = %s\n",
+                               contacts_svc_value_get_str(cursor->data, CTS_EMAIL_VAL_ADDR_STR));
+       }
+
+       get_list = NULL;
+       contacts_svc_struct_get_list(contact, CTS_CF_POSTAL_ADDR_LIST, &get_list);
+       for (cursor = get_list;cursor;cursor=cursor->next)
+       {
+               printf(">>> Postal(type = %d) <<<\n",
+                               contacts_svc_value_get_int(cursor->data, CTS_POSTAL_VAL_TYPE_INT));
+               if ((tmp_str = contacts_svc_value_get_str(cursor->data, CTS_POSTAL_VAL_POBOX_STR)))
+                       printf("Pobox = %s\n", tmp_str);
+               if ((tmp_str = contacts_svc_value_get_str(cursor->data, CTS_POSTAL_VAL_POSTALCODE_STR)))
+                       printf("POSTALCODE = %s\n", tmp_str);
+               if ((tmp_str = contacts_svc_value_get_str(cursor->data, CTS_POSTAL_VAL_LOCALITY_STR)))
+                       printf("LOCALITY = %s\n", tmp_str);
+               if ((tmp_str = contacts_svc_value_get_str(cursor->data, CTS_POSTAL_VAL_STREET_STR)))
+                       printf("STREET = %s\n", tmp_str);
+               if ((tmp_str = contacts_svc_value_get_str(cursor->data, CTS_POSTAL_VAL_EXTENDED_STR)))
+                       printf("EXTENDED = %s\n", tmp_str);
+               if ((tmp_str = contacts_svc_value_get_str(cursor->data, CTS_POSTAL_VAL_COUNTRY_STR)))
+                       printf("COUNTRY = %s\n", tmp_str);
+       }
+       get_list = NULL;
+       contacts_svc_struct_get_list(contact, CTS_CF_EVENT_LIST, &get_list);
+       for (cursor = get_list;cursor;cursor=cursor->next)
+       {
+               printf("type=%d:%d\n",
+                               contacts_svc_value_get_int(cursor->data, CTS_EVENT_VAL_TYPE_INT),
+                               contacts_svc_value_get_int(cursor->data, CTS_EVENT_VAL_DATE_INT));
+       }
+}
+
+static int vcard_handler(const char *vcard, void *data)
+{
+       int ret;
+       CTSstruct *new_contact = NULL;
+
+       ret = contacts_svc_get_contact_from_vcard(vcard, &new_contact);
+       if (CTS_SUCCESS == ret) {
+               get_contact(new_contact);
+               contacts_svc_struct_free(new_contact);
+       }
+
+       contacts_svc_insert_vcard(0, vcard);
+       contacts_svc_replace_by_vcard(1, vcard);
+
+       return CTS_SUCCESS;
+}
+
+int main(int argc, char **argv)
+{
+       if (argc < 2) return -1;
+       contacts_svc_connect();
+
+       printf("vcard file has %d vcards\n", contacts_svc_vcard_count(argv[1]));
+       contacts_svc_vcard_foreach(argv[1], vcard_handler, NULL);
+
+       contacts_svc_disconnect();
+
+       return 0;
+}