diff options
Diffstat (limited to 'src')
40 files changed, 19171 insertions, 0 deletions
diff --git a/src/cts-addressbook.c b/src/cts-addressbook.c new file mode 100755 index 0000000..bb7d516 --- /dev/null +++ b/src/cts-addressbook.c @@ -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 index 0000000..efd64ab --- /dev/null +++ b/src/cts-addressbook.h @@ -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 index 0000000..b090565 --- /dev/null +++ b/src/cts-contact.c @@ -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 index 0000000..85b1a2b --- /dev/null +++ b/src/cts-contact.h @@ -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 index 0000000..55a2c9a --- /dev/null +++ b/src/cts-errors.h @@ -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 index 0000000..c2d2655 --- /dev/null +++ b/src/cts-favorite.c @@ -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 index 0000000..f62c02f --- /dev/null +++ b/src/cts-favorite.h @@ -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 index 0000000..808144a --- /dev/null +++ b/src/cts-group.c @@ -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 index 0000000..472b68f --- /dev/null +++ b/src/cts-group.h @@ -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 index 0000000..553fe3c --- /dev/null +++ b/src/cts-inotify.c @@ -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 index 0000000..5d092f7 --- /dev/null +++ b/src/cts-inotify.h @@ -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 index 0000000..66cc489 --- /dev/null +++ b/src/cts-internal.h @@ -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 index 0000000..96e23b9 --- /dev/null +++ b/src/cts-list-info.c @@ -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 index 0000000..cb289b0 --- /dev/null +++ b/src/cts-list.c @@ -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 index 0000000..93a3356 --- /dev/null +++ b/src/cts-list.h @@ -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 index 0000000..cd003ef --- /dev/null +++ b/src/cts-normalize.c @@ -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 index 0000000..644e9a1 --- /dev/null +++ b/src/cts-normalize.h @@ -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 index 0000000..003c1ef --- /dev/null +++ b/src/cts-phonelog.c @@ -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 index 0000000..19b0a71 --- /dev/null +++ b/src/cts-phonelog.h @@ -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 index 0000000..14a073c --- /dev/null +++ b/src/cts-pthread.c @@ -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 index 0000000..16a5132 --- /dev/null +++ b/src/cts-pthread.h @@ -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 index 0000000..8f72597 --- /dev/null +++ b/src/cts-schema.h @@ -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 index 0000000..280716c --- /dev/null +++ b/src/cts-service.c @@ -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 index 0000000..3c358e8 --- /dev/null +++ b/src/cts-service.h @@ -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 index 0000000..29dbf8c --- /dev/null +++ b/src/cts-socket.c @@ -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 index 0000000..4aa8278 --- /dev/null +++ b/src/cts-socket.h @@ -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 index 0000000..48eebbd --- /dev/null +++ b/src/cts-sqlite.c @@ -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 index 0000000..044a3d4 --- /dev/null +++ b/src/cts-sqlite.h @@ -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 index 0000000..79032cb --- /dev/null +++ b/src/cts-struct-ext.c @@ -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 index 0000000..88c373c --- /dev/null +++ b/src/cts-struct-ext.h @@ -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 index 0000000..e701f2c --- /dev/null +++ b/src/cts-struct.c @@ -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 index 0000000..bd5b1db --- /dev/null +++ b/src/cts-struct.h @@ -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 index 0000000..0cab02f --- /dev/null +++ b/src/cts-types.c @@ -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 index 0000000..6e81b8f --- /dev/null +++ b/src/cts-types.h @@ -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 index 0000000..8bec57c --- /dev/null +++ b/src/cts-utils.c @@ -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 index 0000000..6350fc8 --- /dev/null +++ b/src/cts-utils.h @@ -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 index 0000000..cf8e6ce --- /dev/null +++ b/src/cts-vcard-file.c @@ -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 index 0000000..a82d6be --- /dev/null +++ b/src/cts-vcard-file.h @@ -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 index 0000000..8f02dfc --- /dev/null +++ b/src/cts-vcard.c @@ -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 index 0000000..1f73b42 --- /dev/null +++ b/src/cts-vcard.h @@ -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__ + |