4 * Copyright (c) 2010 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 #include "ctsvc_internal.h"
22 #include "ctsvc_db_schema.h"
23 #include "ctsvc_db_sqlite.h"
24 #include "ctsvc_db_init.h"
25 #include "ctsvc_db_utils.h"
26 #include "ctsvc_notification.h"
27 #include "ctsvc_db_plugin_person_helper.h"
28 #include "ctsvc_db_plugin_contact_helper.h"
29 #include "ctsvc_db_access_control.h"
30 #include "ctsvc_notify.h"
31 #include "ctsvc_number_utils.h"
32 #include "ctsvc_server_setting.h"
33 #include "ctsvc_list.h"
34 #include "ctsvc_localize.h"
36 #ifdef ENABLE_LOG_FEATURE
37 #include "ctsvc_server_phonelog.h"
38 #endif /* ENABLE_LOG_FEATURE */
40 #ifdef _CONTACTS_IPC_SERVER
41 #include "ctsvc_server_change_subject.h"
44 #define CTSVC_COMP_NAME_LEN 4
45 #define CTSVC_AGGREGATION_SUGGESTION_SCORE 2
48 CTSVC_GET_PERSON_DEFAULT_NUMBER_VALUE,
49 CTSVC_GET_PERSON_DEFAULT_EMAIL_VALUE,
50 CTSVC_GET_PERSON_DEFAULT_IMAGE_VALUE,
53 static inline int __ctsvc_get_person_default_number_value(int id, contacts_record_h *record)
57 ctsvc_number_s *number;
58 char query[CTS_SQL_MAX_LEN] = {0};
60 snprintf(query, sizeof(query),
61 "SELECT data.id, data.is_default, data.data1, data.data2, data.data3, data.data4 "
62 "FROM %s, %s ON data.is_primary_default=1 AND data.datatype=%d "
63 "AND data.contact_id = contacts.contact_id AND contacts.deleted = 0 "
64 "WHERE contacts.person_id = %d",
65 CTS_TABLE_CONTACTS, CTS_TABLE_DATA, CTSVC_DATA_NUMBER, id);
67 ret = ctsvc_query_prepare(query, &stmt);
68 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
70 ret = ctsvc_stmt_step(stmt);
71 if (1 /*CTS_TRUE*/ != ret) {
72 ctsvc_stmt_finalize(stmt);
73 ERR("ctsvc_stmt_step() Fail(%d)", ret);
74 if (CONTACTS_ERROR_NONE == ret)
75 return CONTACTS_ERROR_NO_DATA;
80 ret = contacts_record_create(_contacts_number._uri, (contacts_record_h*)&number);
83 number->id = ctsvc_stmt_get_int(stmt, 0);
84 number->is_default = ctsvc_stmt_get_int(stmt, 1);
85 number->type = ctsvc_stmt_get_int(stmt, 2);
86 temp = ctsvc_stmt_get_text(stmt, 3);
87 number->label = SAFE_STRDUP(temp);
88 temp = ctsvc_stmt_get_text(stmt, 4);
89 number->number = SAFE_STRDUP(temp);
90 temp = ctsvc_stmt_get_text(stmt, 5);
91 number->lookup = SAFE_STRDUP(temp);
93 *record = (contacts_record_h)number;
94 ret = CONTACTS_ERROR_NONE;
96 ERR("contacts_record_create() Fail");
99 ctsvc_stmt_finalize(stmt);
103 static inline int __ctsvc_get_person_default_email_value(int id, contacts_record_h *record)
107 ctsvc_email_s *email;
108 char query[CTS_SQL_MAX_LEN] = {0};
110 snprintf(query, sizeof(query),
111 "SELECT data.id, data.is_default, data.data1, data.data2, data.data3 "
112 "FROM %s, %s ON data.is_primary_default=1 AND data.datatype=%d "
113 "AND data.contact_id = contacts.contact_id AND contacts.deleted = 0 "
114 "WHERE contacts.person_id = %d",
115 CTS_TABLE_CONTACTS, CTS_TABLE_DATA, CTSVC_DATA_EMAIL, id);
117 ret = ctsvc_query_prepare(query, &stmt);
118 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
120 ret = ctsvc_stmt_step(stmt);
121 if (1 /*CTS_TRUE*/ != ret) {
122 ctsvc_stmt_finalize(stmt);
123 ERR("ctsvc_stmt_step() Fail(%d)", ret);
124 if (CONTACTS_ERROR_NONE == ret)
125 return CONTACTS_ERROR_NO_DATA;
130 ret = contacts_record_create(_contacts_email._uri, (contacts_record_h*)&email);
133 email->id = ctsvc_stmt_get_int(stmt, 0);
134 email->is_default = ctsvc_stmt_get_int(stmt, 1);
135 email->type = ctsvc_stmt_get_int(stmt, 2);
136 temp = ctsvc_stmt_get_text(stmt, 3);
137 email->label = SAFE_STRDUP(temp);
138 temp = ctsvc_stmt_get_text(stmt, 4);
139 email->email_addr = SAFE_STRDUP(temp);
141 *record = (contacts_record_h)email;
142 ret = CONTACTS_ERROR_NONE;
144 ERR("contacts_record_create() Fail");
147 ctsvc_stmt_finalize(stmt);
151 static inline int __ctsvc_get_person_default_image_value(int id, contacts_record_h *record)
155 ctsvc_image_s *image;
156 char query[CTS_SQL_MAX_LEN] = {0};
158 snprintf(query, sizeof(query),
159 "SELECT data.id, data.is_default, data.data1, data.data2, data.data3 "
160 "FROM "CTS_TABLE_CONTACTS", "CTS_TABLE_DATA" "
161 "ON data.is_primary_default=1 AND data.datatype=%d AND data.is_my_profile = 0 "
162 "AND data.contact_id = contacts.contact_id AND contacts.deleted = 0 "
163 "WHERE contacts.person_id = %d",
164 CTSVC_DATA_IMAGE, id);
166 ret = ctsvc_query_prepare(query, &stmt);
167 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
169 ret = ctsvc_stmt_step(stmt);
170 if (1 /*CTS_TRUE*/ != ret) {
171 ctsvc_stmt_finalize(stmt);
172 ERR("ctsvc_stmt_step() Fail(%d)", ret);
173 if (CONTACTS_ERROR_NONE == ret)
174 return CONTACTS_ERROR_NO_DATA;
179 ret = contacts_record_create(_contacts_image._uri, (contacts_record_h*)&image);
182 image->id = ctsvc_stmt_get_int(stmt, 0);
183 image->is_default = ctsvc_stmt_get_int(stmt, 1);
184 image->type = ctsvc_stmt_get_int(stmt, 2);
185 temp = ctsvc_stmt_get_text(stmt, 3);
186 image->label = SAFE_STRDUP(temp);
187 temp = ctsvc_stmt_get_text(stmt, 4);
188 image->path = SAFE_STRDUP(temp);
190 *record = (contacts_record_h)image;
191 ret = CONTACTS_ERROR_NONE;
193 ERR("contacts_record_create() Fail");
196 ctsvc_stmt_finalize(stmt);
200 static int __ctsvc_get_person_value(int op_code,
201 int person_id, contacts_record_h *record)
205 RETV_IF(NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
208 case CTSVC_GET_PERSON_DEFAULT_NUMBER_VALUE:
209 ret = __ctsvc_get_person_default_number_value(person_id, record);
210 RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "__ctsvc_get_person_default_number_value() Fail(%d)", ret);
212 case CTSVC_GET_PERSON_DEFAULT_EMAIL_VALUE:
213 ret = __ctsvc_get_person_default_email_value(person_id, record);
214 RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "__ctsvc_get_person_default_email_value() Fail(%d)", ret);
216 case CTSVC_GET_PERSON_DEFAULT_IMAGE_VALUE:
217 ret = __ctsvc_get_person_default_image_value(person_id, record);
218 RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "__ctsvc_get_person_default_image_value() Fail(%d)", ret);
221 ERR("The op_code(%d) is not supported", op_code);
222 return CONTACTS_ERROR_INVALID_PARAMETER;
226 return CONTACTS_ERROR_NO_DATA;
231 static inline int __ctsvc_put_person_default_name(int person_id, int contact_id)
235 char query[CTS_SQL_MAX_LEN] = {0};
237 snprintf(query, sizeof(query),
238 "SELECT person_id FROM %s WHERE contact_id=%d AND deleted = 0",
239 CTS_TABLE_CONTACTS, contact_id);
241 ret = ctsvc_query_get_first_int_result(query, &id);
242 RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "ctsvc_query_get_first_int_result() Fail(%d)", ret);
244 if (id == person_id) {
245 ret = ctsvc_begin_trans();
246 RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_begin_trans() Fail(%d)", ret);
247 snprintf(query, sizeof(query),
248 "UPDATE %s SET name_contact_id=%d WHERE person_id=%d",
249 CTS_TABLE_PERSONS, contact_id, person_id);
251 ret = ctsvc_query_exec(query);
252 if (CONTACTS_ERROR_NONE != ret) {
253 ERR("ctsvc_query_exec() Fail(%d)", ret);
254 ctsvc_end_trans(false);
257 ret = ctsvc_end_trans(true);
258 if (ret < CONTACTS_ERROR_NONE) {
259 ERR("ctsvc_end_trans() Fail(%d)", ret);
262 return CONTACTS_ERROR_NONE;
266 ERR("contact(%d) does not belong to person(%d), to person(%d)", contact_id, person_id, ret);
267 ret = CONTACTS_ERROR_NO_DATA;
273 static inline int __ctsvc_put_person_default_image(int person_id, int id)
280 char query[CTS_SQL_MAX_LEN] = {0};
282 ret = ctsvc_begin_trans();
283 RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_begin_trans() Fail(%d)", ret);
285 snprintf(query, sizeof(query),
286 "SELECT D.is_default, D.contact_id, D.data3 "
287 "FROM "CTS_TABLE_DATA" D, "CTS_TABLE_CONTACTS" C "
288 "ON D.contact_id = C.contact_id AND C.deleted = 0 "
289 "WHERE D.datatype=%d AND D.is_my_profile = 0 AND C.person_id=%d AND D.id=%d",
290 CTSVC_DATA_IMAGE, person_id, id);
291 ret = ctsvc_query_prepare(query, &stmt);
293 ERR("ctsvc_query_prepare Fail(%d)", ret);
294 ctsvc_end_trans(false);
298 ret = ctsvc_stmt_step(stmt);
300 ctsvc_stmt_finalize(stmt);
301 ctsvc_end_trans(false);
305 is_default = ctsvc_stmt_get_int(stmt, 0);
306 contact_id = ctsvc_stmt_get_int(stmt, 1);
307 image_path = SAFE_STRDUP(ctsvc_stmt_get_text(stmt, 2));
308 ctsvc_stmt_finalize(stmt);
310 /* unset is_primary_default of all data of the person */
311 snprintf(query, sizeof(query),
312 "UPDATE "CTS_TABLE_DATA" SET is_primary_default=0 WHERE datatype=%d AND is_my_profile = 0 "
313 "AND contact_id IN (SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
314 "WHERE person_id=%d AND deleted = 0) ",
315 CTSVC_DATA_IMAGE, person_id);
316 ret = ctsvc_query_exec(query);
317 if (ret < CONTACTS_ERROR_NONE) {
318 ERR("ctsvc_query_exec() Fail(%d)", ret);
320 ctsvc_end_trans(false);
324 /* unset is_default of all data of person if the data is not default */
325 if (false == is_default) {
326 snprintf(query, sizeof(query),
327 "UPDATE "CTS_TABLE_DATA" SET is_default=0 WHERE datatype=%d AND is_my_profile = 0 "
328 "AND contact_id = (SELECT contact_id FROM "CTS_TABLE_DATA" WHERE id=%d) ",
329 CTSVC_DATA_IMAGE, id);
331 ret = ctsvc_query_exec(query);
332 if (CONTACTS_ERROR_NONE != ret) {
333 ERR("ctsvc_query_exec() Fail(%d)", ret);
335 ctsvc_end_trans(false);
340 /* set is_default, is _primary_default */
341 snprintf(query, sizeof(query),
342 "UPDATE "CTS_TABLE_DATA" SET is_primary_default=1, is_default=1 WHERE id=%d ", id);
343 ret = ctsvc_query_exec(query);
344 if (CONTACTS_ERROR_NONE != ret) {
345 ERR("ctsvc_query_exec() Fail(%d)", ret);
347 ctsvc_end_trans(false);
351 /* update person's image_thumbnail_path */
352 snprintf(query, sizeof(query),
353 "UPDATE "CTS_TABLE_PERSONS" SET image_thumbnail_path=? WHERE person_id=%d ", person_id);
354 ret = ctsvc_query_prepare(query, &stmt);
356 ERR("ctsvc_query_prepare() Fail(%d)", ret);
358 ctsvc_end_trans(false);
362 ctsvc_stmt_bind_text(stmt, 1, image_path);
363 ret = ctsvc_stmt_step(stmt);
364 if (CONTACTS_ERROR_NONE != ret) {
365 ERR("ctsvc_stmt_step() Fail(%d)", ret);
366 ctsvc_stmt_finalize(stmt);
368 ctsvc_end_trans(false);
371 ctsvc_stmt_finalize(stmt);
373 /* update contact's image_thumbnail_path */
374 snprintf(query, sizeof(query),
375 "UPDATE "CTS_TABLE_CONTACTS" SET image_thumbnail_path=? WHERE contact_id=%d ", contact_id);
376 ret = ctsvc_query_prepare(query, &stmt);
378 ERR("ctsvc_query_prepare() Fail(%d)", ret);
380 ctsvc_end_trans(false);
384 ctsvc_stmt_bind_text(stmt, 1, image_path);
385 ret = ctsvc_stmt_step(stmt);
386 if (CONTACTS_ERROR_NONE != ret) {
387 ERR("ctsvc_stmt_step() Fail(%d)", ret);
388 ctsvc_stmt_finalize(stmt);
390 ctsvc_end_trans(false);
393 ctsvc_stmt_finalize(stmt);
397 ret = ctsvc_end_trans(true);
401 static inline int __ctsvc_put_person_default_data(int person_id, int id, int datatype)
406 int name_contact_id = 0;
407 char query[CTS_SQL_MAX_LEN] = {0};
408 cts_stmt stmt = NULL;
409 contacts_display_name_source_type_e source_type = CONTACTS_DISPLAY_NAME_SOURCE_TYPE_INVALID;
411 snprintf(query, sizeof(query),
412 "SELECT D.is_default, D.contact_id FROM %s D, %s C "
413 "ON (D.contact_id=C.contact_id AND C.deleted = 0) "
414 "WHERE D.datatype=%d AND C.person_id=%d AND D.id=%d",
415 CTS_TABLE_DATA, CTS_TABLE_CONTACTS, datatype, person_id, id);
417 ret = ctsvc_query_prepare(query, &stmt);
418 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
420 ret = ctsvc_stmt_step(stmt);
422 ERR("ctsvc_stmt_step() Fail(%d)", ret);
423 ctsvc_stmt_finalize(stmt);
427 is_default = ctsvc_stmt_get_int(stmt, 0);
428 contact_id = ctsvc_stmt_get_int(stmt, 1);
430 ctsvc_stmt_finalize(stmt);
432 ret = ctsvc_begin_trans();
433 RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_begin_trans() Fail(%d)", ret);
435 /* unset is_primary_default of all data of the person */
436 snprintf(query, sizeof(query),
437 "UPDATE "CTS_TABLE_DATA" SET is_primary_default=0 WHERE datatype=%d AND is_my_profile = 0 "
438 "AND contact_id IN (SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
439 "WHERE person_id=%d AND deleted = 0) ",
440 datatype, person_id);
442 ret = ctsvc_query_exec(query);
443 if (ret < CONTACTS_ERROR_NONE) {
444 ERR("ctsvc_query_exec() Fail(%d)", ret);
445 ctsvc_end_trans(false);
449 /* unset is_default of all data of person if the data is not default */
450 if (false == is_default) {
451 snprintf(query, sizeof(query),
452 "UPDATE "CTS_TABLE_DATA" SET is_default=0 WHERE datatype=%d AND is_my_profile = 0 "
453 "AND contact_id = (SELECT contact_id FROM "CTS_TABLE_DATA" WHERE id=%d) ",
456 ret = ctsvc_query_exec(query);
457 if (CONTACTS_ERROR_NONE != ret) {
458 ERR("ctsvc_query_exec() Fail(%d)", ret);
459 ctsvc_end_trans(false);
464 /* set is_default, is _primary_default */
465 snprintf(query, sizeof(query),
466 "UPDATE "CTS_TABLE_DATA" SET is_primary_default=1, is_default=1 WHERE id=%d ", id);
468 ret = ctsvc_query_exec(query);
469 if (CONTACTS_ERROR_NONE != ret) {
470 ERR("ctsvc_query_exec() Fail(%d)", ret);
471 ctsvc_end_trans(false);
475 if (datatype == CTSVC_DATA_NUMBER)
476 source_type = CONTACTS_DISPLAY_NAME_SOURCE_TYPE_NUMBER;
477 else if (datatype == CTSVC_DATA_EMAIL)
478 source_type = CONTACTS_DISPLAY_NAME_SOURCE_TYPE_EMAIL;
480 if (CONTACTS_DISPLAY_NAME_SOURCE_TYPE_INVALID != source_type)
481 ctsvc_contact_update_display_name(contact_id, source_type);
483 snprintf(query, sizeof(query),
484 "SELECT name_contact_id FROM "CTS_TABLE_PERSONS" WHERE person_id = %d", person_id);
485 ret = ctsvc_query_get_first_int_result(query, &name_contact_id);
486 if (CONTACTS_ERROR_NONE != ret) {
487 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
488 ctsvc_end_trans(false);
492 if (name_contact_id != contact_id) {
493 int org_source_type = CONTACTS_DISPLAY_NAME_SOURCE_TYPE_INVALID;
494 snprintf(query, sizeof(query),
495 "SELECT display_name_source FROM "CTS_TABLE_CONTACTS" WHERE contact_id = %d", name_contact_id);
496 ret = ctsvc_query_get_first_int_result(query, &org_source_type);
497 if (CONTACTS_ERROR_NONE != ret) {
498 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
499 ctsvc_end_trans(false);
503 if (org_source_type <= source_type) {
504 snprintf(query, sizeof(query),
505 "UPDATE %s SET name_contact_id=%d WHERE person_id=%d",
506 CTS_TABLE_PERSONS, contact_id, person_id);
507 ret = ctsvc_query_exec(query);
508 if (CONTACTS_ERROR_NONE != ret) {
509 ERR("ctsvc_query_exec() Fail(%d)", ret);
510 ctsvc_end_trans(false);
516 ret = ctsvc_end_trans(true);
517 if (ret < CONTACTS_ERROR_NONE) {
518 ERR("ctsvc_end_trans() Fail(%d)", ret);
521 return CONTACTS_ERROR_NONE;
525 void ctsvc_db_person_delete_callback(sqlite3_context *context,
526 int argc, sqlite3_value **argv)
528 #ifdef _CONTACTS_IPC_SERVER
532 sqlite3_result_null(context);
536 person_id = sqlite3_value_int(argv[0]);
537 ctsvc_change_subject_add_changed_person_id(CONTACTS_CHANGE_DELETED, person_id);
539 #ifdef ENABLE_LOG_FEATURE
542 * CASE : do not know the proper new person_id
544 ctsvc_db_phone_log_update_person_id(NULL, person_id, -1, false);
545 #endif /* ENABLE_LOG_FEATURE */
546 sqlite3_result_null(context);
551 static inline const char *__ctsvc_get_image_filename(const char *src)
553 const char *dir = CTSVC_CONTACT_IMG_FULL_LOCATION;
555 while (dir[pos] == src[pos])
559 return src + pos + 1;
564 int ctsvc_person_aggregate(int person_id)
570 char *addressbook_ids = NULL;
571 int addressbooks_len = 100;
572 int name_contact_id = 0;
573 int person_name_contact_id = 0;
574 int display_name_source_type = CONTACTS_DISPLAY_NAME_SOURCE_TYPE_INVALID;
575 char query[CTS_SQL_MIN_LEN] = {0};
576 char *ringtone_path = NULL;
577 char *image_thumbnail_path = NULL;
578 char *vibration = NULL;
579 char *message_alert = NULL;
583 ctsvc_person_s *person;
584 bool person_is_favorite = false;
587 * person aggregation : person link/unlink, contact insert (auto link),
588 * contact delete, garbage collection (addressbook delete)
589 * It should be get all contacts of person regardless of permission
590 * Get person info directly instead of contacts_db_get_record(_contacts_person._uri, person_id, (contacts_record_h*)&person);
592 snprintf(query, sizeof(query),
595 "image_thumbnail_path, "
599 "FROM "CTS_TABLE_PERSONS" "
600 "WHERE persons.person_id = %d", person_id);
601 ret = ctsvc_query_prepare(query, &stmt);
602 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
604 if (1 != ctsvc_stmt_step(stmt)) {
605 ERR("ctsvc_stmt_step() Fail\n");
606 return CONTACTS_ERROR_DB;
608 ret = contacts_record_create(_contacts_person._uri, (contacts_record_h*)&person);
609 if (CONTACTS_ERROR_NONE != ret) {
610 ERR("contacts_record_create() Fail\n");
611 return CONTACTS_ERROR_INTERNAL;
613 person->person_id = ctsvc_stmt_get_int(stmt, 0);
614 person->name_contact_id = ctsvc_stmt_get_int(stmt, 1);
615 temp = ctsvc_stmt_get_text(stmt, 2);
616 person->image_thumbnail_path = SAFE_STRDUP(temp);
617 temp = ctsvc_stmt_get_text(stmt, 3);
618 person->ringtone_path = SAFE_STRDUP(temp);
619 temp = ctsvc_stmt_get_text(stmt, 4);
620 person->vibration = SAFE_STRDUP(temp);
621 temp = ctsvc_stmt_get_text(stmt, 5);
622 person->message_alert = SAFE_STRDUP(temp);
623 ctsvc_stmt_finalize(stmt);
625 /* check image_thumbnail_path */
626 if (person->image_thumbnail_path) {
627 temp = __ctsvc_get_image_filename(person->image_thumbnail_path);
628 snprintf(query, sizeof(query),
629 "SELECT D.id FROM "CTS_TABLE_CONTACTS" C, "CTS_TABLE_DATA" D "
630 "WHERE C.person_id=%d AND C.contact_id=D.contact_id AND C.deleted = 0 "
631 "AND D.datatype=%d AND D.is_primary_default = 1 AND D.data3='%s'",
632 person->person_id, CTSVC_DATA_IMAGE, temp);
633 ret = ctsvc_query_get_first_int_result(query, &id);
634 if (ret == CONTACTS_ERROR_NONE)
635 image_thumbnail_path = SAFE_STRDUP(temp);
637 image_thumbnail_path = NULL;
640 /* check name_contact_id */
641 snprintf(query, sizeof(query),
642 "SELECT contact_id FROM %s "
643 "WHERE person_id=%d AND contact_id=%d AND deleted = 0",
644 CTS_TABLE_CONTACTS, person->person_id, person->name_contact_id);
646 ret = ctsvc_query_get_first_int_result(query, &id);
647 if (ret == CONTACTS_ERROR_NONE) {
648 name_contact_id = person->name_contact_id;
649 person_name_contact_id = person->name_contact_id;
652 person_name_contact_id = 0;
655 /* get status of person */
656 snprintf(query, sizeof(query),
657 "SELECT a.status FROM %s c, %s a "
658 "ON c.contact_id = a.contact_id AND c.deleted = 0 "
659 "WHERE c.person_id=%d "
660 "ORDER BY timestamp DESC LIMIT 1",
661 CTS_TABLE_CONTACTS, CTS_TABLE_ACTIVITIES, person->person_id);
662 ret = ctsvc_query_prepare(query, &stmt);
664 ERR("ctsvc_query_prepare() Fail(%d)", ret);
665 free(image_thumbnail_path);
666 contacts_record_destroy((contacts_record_h)person, true);
670 if (1 == ctsvc_stmt_step(stmt)) {
671 temp = ctsvc_stmt_get_text(stmt, 0);
672 status = SAFE_STRDUP(temp);
674 ctsvc_stmt_finalize(stmt);
676 /* check ringtone_path */
677 if (person->ringtone_path) {
678 snprintf(query, sizeof(query),
679 "SELECT C.contact_id FROM "CTS_TABLE_CONTACTS" C "
680 "WHERE C.person_id=%d AND C.deleted = 0 "
681 "AND C.ringtone_path = '%s'",
682 person->person_id, person->ringtone_path);
683 ret = ctsvc_query_get_first_int_result(query, &id);
684 if (ret == CONTACTS_ERROR_NONE)
685 ringtone_path = SAFE_STRDUP(person->ringtone_path);
687 ringtone_path = NULL;
690 /* check vibration */
691 if (person->vibration) {
692 snprintf(query, sizeof(query),
693 "SELECT C.contact_idFROM "CTS_TABLE_CONTACTS" C "
694 "WHERE C.person_id=%d AND C.deleted = 0 "
695 "AND C.vibration = '%s'",
696 person->person_id, person->vibration);
697 ret = ctsvc_query_get_first_int_result(query, &id);
698 if (ret == CONTACTS_ERROR_NONE)
699 vibration = SAFE_STRDUP(person->vibration);
704 /* check vibration */
705 if (person->message_alert) {
706 snprintf(query, sizeof(query),
707 "SELECT C.contact_id FROM "CTS_TABLE_CONTACTS" C "
708 "WHERE C.person_id=%d AND C.deleted = 0 "
709 "AND C.message_alert = '%s'",
710 person->person_id, person->message_alert);
711 ret = ctsvc_query_get_first_int_result(query, &id);
712 if (ret == CONTACTS_ERROR_NONE)
713 message_alert = SAFE_STRDUP(person->message_alert);
715 message_alert = NULL;
717 contacts_record_destroy((contacts_record_h)person, true);
719 snprintf(query, sizeof(query),
720 "SELECT contact_id, contacts.addressbook_id, display_name_source, "
721 "image_thumbnail_path, ringtone_path, vibration, message_alert, is_favorite "
723 "WHERE person_id = %d AND contacts.deleted = 0 "
724 "ORDER BY contact_id",
725 CTS_TABLE_CONTACTS, person_id);
726 ret = ctsvc_query_prepare(query, &stmt);
728 ERR("ctsvc_query_prepare() Fail(%d)", ret);
729 free(image_thumbnail_path);
739 while ((ret = ctsvc_stmt_step(stmt))) {
740 const char *temp_str;
744 int contact_display_name_source_type = CONTACTS_DISPLAY_NAME_SOURCE_TYPE_INVALID;
745 char *contact_ringtone_path = NULL;
746 char *contact_image_thumbnail_path = NULL;
747 char *contact_vibration = NULL;
748 char *contact_message_alert = NULL;
749 bool is_favorite = false;
753 contact_id = ctsvc_stmt_get_int(stmt, i++);
754 addressbook_id = ctsvc_stmt_get_int(stmt, i++);
755 contact_display_name_source_type = ctsvc_stmt_get_int(stmt, i++);
756 temp = ctsvc_stmt_get_text(stmt, i++);
758 contact_image_thumbnail_path = strdup(temp);
759 temp = ctsvc_stmt_get_text(stmt, i++);
760 contact_ringtone_path = SAFE_STRDUP(temp);
761 temp = ctsvc_stmt_get_text(stmt, i++);
762 contact_vibration = SAFE_STRDUP(temp);
763 temp = ctsvc_stmt_get_text(stmt, i++);
764 contact_message_alert = SAFE_STRDUP(temp);
765 is_favorite = ctsvc_stmt_get_int(stmt, i++);
769 if (display_name_source_type < contact_display_name_source_type) {
770 display_name_source_type = contact_display_name_source_type;
771 name_contact_id = contact_id;
772 } else if (contact_display_name_source_type == display_name_source_type) {
773 if (name_contact_id != person_name_contact_id && person_name_contact_id != 0)
774 name_contact_id = person_name_contact_id;
775 else if (person_name_contact_id == 0 && name_contact_id == 0)
776 name_contact_id = contact_id;
779 addr_len = snprintf(addr, sizeof(addr), "%d%s", addressbook_id, ADDRESSBOOK_ID_DELIM);
780 if (NULL == addressbook_ids)
781 addressbook_ids = calloc(addressbooks_len+1, sizeof(char));
782 else if (addressbooks_len <= strlen(addressbook_ids)+addr_len) {
783 addressbooks_len = MAX(addressbooks_len*2, strlen(addressbook_ids)+addr_len+1);
784 addressbook_ids = realloc(addressbook_ids, addressbooks_len);
787 len += snprintf(addressbook_ids + len, addressbooks_len -len, "%d%s", addressbook_id, ADDRESSBOOK_ID_DELIM);
789 if (NULL == image_thumbnail_path && contact_image_thumbnail_path && *contact_image_thumbnail_path) {
790 temp = __ctsvc_get_image_filename(contact_image_thumbnail_path);
791 image_thumbnail_path = SAFE_STRDUP(temp);
792 /* update data table : is_primary_default */
794 free(contact_image_thumbnail_path);
796 temp_str = contact_ringtone_path;
797 if (NULL == ringtone_path && temp_str && strlen(temp_str))
798 ringtone_path = SAFE_STRDUP(temp_str);
799 free(contact_ringtone_path);
801 temp_str = contact_vibration;
802 if (NULL == vibration && temp_str && strlen(temp_str))
803 vibration = SAFE_STRDUP(temp_str);
804 free(contact_vibration);
806 temp_str = contact_message_alert;
807 if (NULL == message_alert && temp_str && strlen(temp_str))
808 message_alert = SAFE_STRDUP(temp_str);
809 free(contact_message_alert);
812 person_is_favorite = true;
814 ctsvc_stmt_finalize(stmt);
815 version = ctsvc_get_next_ver();
817 snprintf(query, sizeof(query),
818 "UPDATE "CTS_TABLE_PERSONS" SET dirty=0, name_contact_id = %d, changed_ver = %d, "
819 "has_phonenumber = EXISTS(SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
820 "WHERE person_id = %d AND has_phonenumber = 1 AND deleted = 0), "
821 "has_email = EXISTS(SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
822 "WHERE person_id = %d AND has_email = 1 AND deleted = 0), "
823 "link_count = %d, addressbook_ids = ?, ringtone_path=?, vibration=?, message_alert=?, status=?, image_thumbnail_path=? "
824 "WHERE person_id = %d ",
825 name_contact_id, version, person_id,
826 person_id, link_count, person_id);
828 ret = ctsvc_query_prepare(query, &stmt);
830 ERR("ctsvc_query_prepare() Fail(%d)", ret);
831 free(addressbook_ids);
832 free(image_thumbnail_path);
841 ctsvc_stmt_bind_text(stmt, 1, addressbook_ids);
843 ctsvc_stmt_bind_text(stmt, 2, ringtone_path);
845 ctsvc_stmt_bind_text(stmt, 3, vibration);
847 ctsvc_stmt_bind_text(stmt, 4, message_alert);
849 ctsvc_stmt_bind_text(stmt, 5, status);
850 if (image_thumbnail_path)
851 ctsvc_stmt_bind_text(stmt, 6, image_thumbnail_path);
853 ret = ctsvc_stmt_step(stmt);
854 if (CONTACTS_ERROR_NONE != ret) {
855 ERR("ctsvc_stmt_step() Fail(%d)", ret);
856 ctsvc_stmt_finalize(stmt);
857 free(addressbook_ids);
858 free(image_thumbnail_path);
866 ctsvc_stmt_finalize(stmt);
868 free(addressbook_ids);
869 free(image_thumbnail_path);
875 if (false == person_is_favorite) {
876 snprintf(query, sizeof(query),
877 "DELETE FROM "CTS_TABLE_FAVORITES" WHERE person_id = %d", person_id);
878 ret = ctsvc_query_exec(query);
879 if (CONTACTS_ERROR_NONE != ret) {
880 ERR("ctsvc_query_exec() Fail(%d)", ret);
885 ctsvc_set_person_noti();
886 #ifdef _CONTACTS_IPC_SERVER
887 ctsvc_change_subject_add_changed_person_id(CONTACTS_CHANGE_UPDATED, person_id);
890 return CONTACTS_ERROR_NONE;
893 static bool __ctsvc_get_person_favorite_info(int person_id, double *priority)
897 char query[CTS_SQL_MIN_LEN] = {0};
898 snprintf(query, sizeof(query),
899 "SELECT favorite_prio FROM "CTS_TABLE_FAVORITES" WHERE person_id = %d", person_id);
900 ret = ctsvc_query_prepare(query, &stmt);
901 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
903 ret = ctsvc_stmt_step(stmt);
905 *priority = ctsvc_stmt_get_dbl(stmt, 0);
906 ctsvc_stmt_finalize(stmt);
909 ctsvc_stmt_finalize(stmt);
913 int ctsvc_person_link_person(int base_person_id, int person_id)
916 char query[CTS_SQL_MIN_LEN] = {0};
917 int default_number_id = 0;
918 int default_email_id = 0;
919 int default_image_id = 0;
920 contacts_record_h record = NULL;
921 bool base_is_favorite = false;
922 bool is_favorite = false;
923 double favorite_prio = 0.0;
925 RETVM_IF(base_person_id == person_id, CONTACTS_ERROR_INVALID_PARAMETER,
926 "base_person_id(%d), person_id(%d)", base_person_id, person_id);
928 ret = ctsvc_begin_trans();
929 RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_begin_trans() Fail(%d)", ret);
931 ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_NUMBER_VALUE, base_person_id, &record);
932 if (CONTACTS_ERROR_NONE != ret) {
933 ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_NUMBER_VALUE, person_id, &record);
934 if (CONTACTS_ERROR_NONE == ret) {
935 contacts_record_get_int(record, CTSVC_PROPERTY_NUMBER_ID, &default_number_id);
936 contacts_record_destroy(record, true);
939 contacts_record_get_int(record, CTSVC_PROPERTY_NUMBER_ID, &default_number_id);
940 contacts_record_destroy(record, true);
943 ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_EMAIL_VALUE, base_person_id, &record);
944 if (CONTACTS_ERROR_NONE != ret) {
945 ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_EMAIL_VALUE, person_id, &record);
946 if (CONTACTS_ERROR_NONE == ret) {
947 contacts_record_get_int(record, CTSVC_PROPERTY_EMAIL_ID, &default_email_id);
948 contacts_record_destroy(record, true);
951 contacts_record_get_int(record, CTSVC_PROPERTY_EMAIL_ID, &default_email_id);
952 contacts_record_destroy(record, true);
955 ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_IMAGE_VALUE, base_person_id, &record);
956 if (CONTACTS_ERROR_NONE != ret) {
957 ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_IMAGE_VALUE, person_id, &record);
958 if (CONTACTS_ERROR_NONE == ret) {
959 contacts_record_get_int(record, CTSVC_PROPERTY_IMAGE_ID, &default_image_id);
960 contacts_record_destroy(record, true);
963 contacts_record_get_int(record, CTSVC_PROPERTY_IMAGE_ID, &default_image_id);
964 contacts_record_destroy(record, true);
967 base_is_favorite = __ctsvc_get_person_favorite_info(base_person_id, &favorite_prio);
968 if (false == base_is_favorite)
969 is_favorite = __ctsvc_get_person_favorite_info(person_id, &favorite_prio);
971 snprintf(query, sizeof(query),
972 "UPDATE %s SET person_id = %d WHERE person_id = %d AND deleted = 0",
973 CTS_TABLE_CONTACTS, base_person_id, person_id);
974 ret = ctsvc_query_exec(query);
975 if (CONTACTS_ERROR_NONE != ret) {
976 ERR("ctsvc_query_exec() Fail(%d)", ret);
977 ctsvc_end_trans(false);
981 ctsvc_person_aggregate(base_person_id);
983 if (default_number_id)
984 __ctsvc_put_person_default_data(base_person_id, default_number_id, CTSVC_DATA_NUMBER);
986 if (default_email_id)
987 __ctsvc_put_person_default_data(base_person_id, default_email_id, CTSVC_DATA_EMAIL);
989 if (default_image_id)
990 __ctsvc_put_person_default_image(base_person_id, default_image_id);
992 #ifdef ENABLE_LOG_FEATURE
995 * Updating phonelog person_id before deleting person
996 * Because, when deleting, ctsvc_db_person_delete_callback will be called
997 * the logic takes more time to find proper person_id (base_person_id)
999 ctsvc_db_phone_log_update_person_id(NULL, person_id, base_person_id, true);
1000 #endif /* ENABLE_LOG_FEATURE */
1002 snprintf(query, sizeof(query), "DELETE FROM %s WHERE person_id = %d",
1003 CTS_TABLE_PERSONS, person_id);
1004 ret = ctsvc_query_exec(query);
1005 if (CONTACTS_ERROR_NONE != ret) {
1006 ERR("ctsvc_query_exec() Fail(%d)", ret);
1007 ctsvc_end_trans(false);
1011 *#ifdef _CONTACTS_IPC_SERVER
1012 * It will be added in ctsvc_db_person_delete_callback
1013 * ctsvc_change_subject_add_changed_person_id(CONTACTS_CHANGE_DELETED, person_id);
1018 snprintf(query, sizeof(query),
1019 "INSERT INTO "CTS_TABLE_FAVORITES" values(%d, %f)", base_person_id, favorite_prio);
1020 ret = ctsvc_query_exec(query);
1021 if (CONTACTS_ERROR_NONE != ret) {
1022 ERR("ctsvc_query_exec() Fail(%d)", ret);
1023 ctsvc_end_trans(false);
1028 ctsvc_set_person_noti();
1029 ret = ctsvc_end_trans(true);
1030 if (ret < CONTACTS_ERROR_NONE) {
1031 ERR("ctsvc_end_trans() Fail(%d)", ret);
1034 return CONTACTS_ERROR_NONE;
1038 static int __ctsvc_update_primary_default_data(int person_id)
1041 contacts_record_h record = NULL;
1042 char query[CTS_SQL_MIN_LEN] = {0};
1045 ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_NUMBER_VALUE, person_id, &record);
1046 if (CONTACTS_ERROR_NONE != ret) {
1047 snprintf(query, sizeof(query),
1048 "SELECT contact_id "
1050 "WHERE person_id = %d AND deleted = 0 "
1051 "ORDER BY contact_id",
1052 CTS_TABLE_CONTACTS, person_id);
1053 ret = ctsvc_query_prepare(query, &stmt);
1054 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1056 while (1 == ctsvc_stmt_step(stmt)) {
1057 int contact_id = ctsvc_stmt_get_int(stmt, 0);
1058 cts_stmt stmt_number;
1060 snprintf(query, sizeof(query),
1061 "SELECT id, is_default FROM %s "
1062 "WHERE contact_id = %d AND datatype = %d AND is_default = 1 AND is_my_profile = 0",
1063 CTS_TABLE_DATA, contact_id, CTSVC_DATA_NUMBER);
1065 ret = ctsvc_query_prepare(query, &stmt_number);
1066 if (NULL == stmt_number) {
1067 ERR("ctsvc_query_prepare() Fail(%d)", ret);
1068 ctsvc_stmt_finalize(stmt);
1072 if (1 == ctsvc_stmt_step(stmt_number)) {
1073 int default_number_id = ctsvc_stmt_get_int(stmt_number, 0);
1074 __ctsvc_put_person_default_data(person_id, default_number_id, CTSVC_DATA_NUMBER);
1075 ctsvc_stmt_finalize(stmt_number);
1078 ctsvc_stmt_finalize(stmt_number);
1080 ctsvc_stmt_finalize(stmt);
1082 contacts_record_destroy(record, true);
1085 ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_EMAIL_VALUE, person_id, &record);
1086 if (CONTACTS_ERROR_NONE != ret) {
1087 snprintf(query, sizeof(query),
1088 "SELECT contact_id "
1090 "WHERE person_id = %d AND deleted = 0 "
1091 "ORDER BY contact_id",
1092 CTS_TABLE_CONTACTS, person_id);
1093 ret = ctsvc_query_prepare(query, &stmt);
1094 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1096 while (1 == ctsvc_stmt_step(stmt)) {
1097 int contact_id = ctsvc_stmt_get_int(stmt, 0);
1098 cts_stmt stmt_email;
1100 snprintf(query, sizeof(query),
1101 "SELECT id, is_default FROM %s "
1102 "WHERE contact_id = %d AND datatype = %d AND is_default = 1 AND is_my_profile = 0",
1103 CTS_TABLE_DATA, contact_id, CTSVC_DATA_EMAIL);
1105 ret = ctsvc_query_prepare(query, &stmt_email);
1106 if (NULL == stmt_email) {
1107 ERR("ctsvc_query_prepare() Fail(%d)", ret);
1108 ctsvc_stmt_finalize(stmt);
1112 if (1 == ctsvc_stmt_step(stmt_email)) {
1113 int default_email_id = ctsvc_stmt_get_int(stmt_email, 0);
1114 __ctsvc_put_person_default_data(person_id, default_email_id, CTSVC_DATA_EMAIL);
1115 ctsvc_stmt_finalize(stmt_email);
1118 ctsvc_stmt_finalize(stmt_email);
1120 ctsvc_stmt_finalize(stmt);
1122 contacts_record_destroy(record, true);
1125 ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_IMAGE_VALUE, person_id, &record);
1126 if (CONTACTS_ERROR_NONE != ret) {
1127 snprintf(query, sizeof(query),
1128 "SELECT contact_id "
1130 "WHERE person_id = %d AND deleted = 0 "
1131 "ORDER BY contact_id",
1132 CTS_TABLE_CONTACTS, person_id);
1133 ret = ctsvc_query_prepare(query, &stmt);
1134 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1136 while (1 == ctsvc_stmt_step(stmt)) {
1137 int contact_id = ctsvc_stmt_get_int(stmt, 0);
1138 cts_stmt stmt_image;
1140 snprintf(query, sizeof(query),
1141 "SELECT id, is_default FROM %s "
1142 "WHERE contact_id = %d AND datatype = %d AND is_default = 1 AND is_my_profile = 0",
1143 CTS_TABLE_DATA, contact_id, CTSVC_DATA_IMAGE);
1145 ret = ctsvc_query_prepare(query, &stmt_image);
1146 if (NULL == stmt_image) {
1147 ERR("ctsvc_query_prepare() Fail(%d)", ret);
1148 ctsvc_stmt_finalize(stmt);
1152 if (1 == ctsvc_stmt_step(stmt_image)) {
1153 int default_image_id = ctsvc_stmt_get_int(stmt_image, 0);
1154 __ctsvc_put_person_default_image(person_id, default_image_id);
1155 ctsvc_stmt_finalize(stmt_image);
1158 ctsvc_stmt_finalize(stmt_image);
1160 ctsvc_stmt_finalize(stmt);
1162 contacts_record_destroy(record, true);
1165 return CONTACTS_ERROR_NONE;
1168 int ctsvc_person_unlink_contact(int person_id, int contact_id, int *out_person_id)
1173 char query[CTS_SQL_MIN_LEN] = {0};
1174 contacts_record_h record = NULL;
1175 bool is_favorite = false;
1176 double priority = 0.0;
1178 RETVM_IF(person_id <= 0 || contact_id <= 0, CONTACTS_ERROR_INVALID_PARAMETER,
1179 "person_id(%d), person_id(%d)", person_id, person_id);
1184 ret = ctsvc_begin_trans();
1185 RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
1187 snprintf(query, sizeof(query),
1188 "SELECT link_count FROM "CTS_TABLE_PERSONS" WHERE person_id=%d", person_id);
1189 ret = ctsvc_query_get_first_int_result(query, &link_count);
1190 if (CONTACTS_ERROR_NONE != ret) {
1191 ctsvc_end_trans(false);
1195 if (link_count == 1) {
1196 ERR("This person(%d) has one contact(%d)", person_id, contact_id);
1197 ctsvc_end_trans(false);
1198 return CONTACTS_ERROR_INVALID_PARAMETER;
1201 ret = ctsvc_db_contact_get(contact_id, (contacts_record_h*)&record);
1202 if (CONTACTS_ERROR_NONE != ret) {
1203 ERR("ctsvc_db_contact_get() Fail(%d)", ret);
1204 ctsvc_end_trans(false);
1208 /* create new person */
1209 id = ctsvc_db_insert_person(record);
1210 if (id < CONTACTS_ERROR_NONE) {
1211 ERR("ctsvc_db_insert_person() Fail(%d)", id);
1212 ctsvc_end_trans(false);
1213 contacts_record_destroy(record, true);
1217 /* insert statistic info for new person */
1218 snprintf(query, sizeof(query),
1219 "INSERT INTO %s (person_id, usage_type, times_used) "
1220 "SELECT %d, usage_type, times_used FROM %s WHERE person_id = %d",
1221 CTS_TABLE_CONTACT_STAT, id, CTS_TABLE_CONTACT_STAT, person_id);
1222 ret = ctsvc_query_exec(query);
1223 if (CONTACTS_ERROR_NONE != ret) {
1224 ERR("ctsvc_query_exec() Fail(%d)", ret);
1225 ctsvc_end_trans(false);
1226 contacts_record_destroy(record, true);
1230 is_favorite = __ctsvc_get_person_favorite_info(person_id, &priority);
1232 /* update person_id of unlinked contact */
1233 snprintf(query, sizeof(query),
1234 "UPDATE %s SET person_id = %d WHERE contact_id = %d",
1235 CTS_TABLE_CONTACTS, id, contact_id);
1236 ret = ctsvc_query_exec(query);
1237 if (CONTACTS_ERROR_NONE != ret) {
1238 ERR("ctsvc_query_exec() Fail(%d)", ret);
1239 ctsvc_end_trans(false);
1240 contacts_record_destroy(record, true);
1244 /* update bsae person info */
1245 ret = ctsvc_person_aggregate(person_id);
1246 if (CONTACTS_ERROR_NONE != ret) {
1247 ERR("ctsvc_person_aggregate(%d) Fail(%d)", person_id, ret);
1248 ctsvc_end_trans(false);
1249 contacts_record_destroy(record, true);
1253 if (is_favorite && ((ctsvc_contact_s*)record)->is_favorite) {
1254 snprintf(query, sizeof(query),
1255 "INSERT OR REPLACE INTO "CTS_TABLE_FAVORITES" values(%d, %f)", id, priority);
1256 ret = ctsvc_query_exec(query);
1257 if (CONTACTS_ERROR_NONE != ret) {
1258 ERR("ctsvc_query_exec() Fail(%d)", ret);
1259 ctsvc_end_trans(false);
1260 contacts_record_destroy(record, true);
1264 contacts_record_destroy(record, true);
1266 __ctsvc_update_primary_default_data(person_id);
1268 #ifdef ENABLE_LOG_FEATURE
1269 /* update phonelog */
1270 ctsvc_db_phone_log_update_person_id(NULL, person_id, id, false);
1271 #endif /* ENABLE_LOG_FEATURE */
1274 *out_person_id = id;
1275 ctsvc_set_person_noti();
1276 ret = ctsvc_end_trans(true);
1277 if (ret < CONTACTS_ERROR_NONE) {
1278 ERR("ctsvc_end_trans() Fail(%d)", ret);
1281 return CONTACTS_ERROR_NONE;
1285 int ctsvc_person_do_garbage_collection(void)
1288 cts_stmt stmt = NULL;
1289 char query[CTS_SQL_MIN_LEN] = {0};
1291 snprintf(query, sizeof(query), "SELECT person_id FROM "CTS_TABLE_PERSONS" WHERE dirty=1");
1293 ret = ctsvc_query_prepare(query, &stmt);
1294 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1296 while (1 /*CTS_TRUE*/ == ctsvc_stmt_step(stmt)) {
1298 person_id = ctsvc_stmt_get_int(stmt, 0);
1299 ctsvc_person_aggregate(person_id);
1300 #ifdef ENABLE_LOG_FEATURE
1301 /* update phonelog */
1302 ctsvc_db_phone_log_update_person_id(NULL, person_id, -1, false);
1303 #endif /* ENABLE_LOG_FEATURE */
1305 ctsvc_stmt_finalize(stmt);
1307 return CONTACTS_ERROR_NONE;
1310 int ctsvc_person_reset_usage(int person_id, contacts_usage_type_e type)
1313 char query[CTS_SQL_MAX_LEN] = {0};
1315 RETVM_IF(person_id <= 0, CONTACTS_ERROR_INVALID_PARAMETER, "contact_id should be greater than 0");
1317 snprintf(query, sizeof(query),
1318 "UPDATE %s SET times_used = 0 WHERE person_id = %d AND usage_type = %d",
1319 CTS_TABLE_CONTACT_STAT, person_id, type);
1321 ret = ctsvc_begin_trans();
1322 RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
1324 ret = ctsvc_query_exec(query);
1325 if (CONTACTS_ERROR_NONE != ret) {
1326 ERR("ctsvc_query_exec() Fail(%d)", ret);
1327 ctsvc_end_trans(false);
1331 ret = ctsvc_end_trans(true);
1332 if (ret < CONTACTS_ERROR_NONE) {
1333 ERR("ctsvc_end_trans() Fail(%d)", ret);
1336 return CONTACTS_ERROR_NONE;
1340 int ctsvc_person_set_favorite_order(int person_id, int front_person_id, int back_person_id)
1343 double front_prio = 0.0;
1344 double back_prio = 0.0;
1347 char query[CTS_SQL_MAX_LEN] = {0};
1349 snprintf(query, sizeof(query), "SELECT favorite_prio FROM "CTS_TABLE_FAVORITES" WHERE person_id = ?");
1351 ret = ctsvc_query_prepare(query, &stmt);
1352 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1354 ctsvc_stmt_bind_int(stmt, 1, front_person_id);
1355 ret = ctsvc_stmt_step(stmt);
1356 if (1 /*CTS_TRUE*/ == ret)
1357 front_prio = ctsvc_stmt_get_dbl(stmt, 0);
1358 ctsvc_stmt_reset(stmt);
1359 ctsvc_stmt_bind_int(stmt, 1, back_person_id);
1360 ret = ctsvc_stmt_step(stmt);
1361 if (1 /*CTS_TRUE*/ == ret)
1362 back_prio = ctsvc_stmt_get_dbl(stmt, 0);
1363 ctsvc_stmt_finalize(stmt);
1365 RETVM_IF(0.0 == front_prio && 0.0 == back_prio, CONTACTS_ERROR_INVALID_PARAMETER,
1366 "The indexes for front and back are invalid.");
1368 if (0.0 == back_prio)
1369 prio = front_prio + 1;
1371 prio = (front_prio + back_prio) / 2;
1373 ret = ctsvc_begin_trans();
1374 RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
1376 snprintf(query, sizeof(query),
1377 "UPDATE %s SET favorite_prio = %f WHERE person_id = %d",
1378 CTS_TABLE_FAVORITES, prio, person_id);
1380 ret = ctsvc_query_exec(query);
1381 if (CONTACTS_ERROR_NONE != ret) {
1382 ERR("ctsvc_query_exec() Fail(%d)", ret);
1383 ctsvc_end_trans(false);
1387 ctsvc_set_person_noti();
1389 ret = ctsvc_end_trans(true);
1390 if (ret < CONTACTS_ERROR_NONE) {
1391 ERR("ctsvc_end_trans() Fail(%d)", ret);
1394 return CONTACTS_ERROR_NONE;
1398 int ctsvc_person_set_default_property(contacts_person_property_e property, int person_id,
1403 ret = ctsvc_begin_trans();
1404 RETVM_IF(ret < CONTACTS_ERROR_NONE, CONTACTS_ERROR_DB, "ctsvc_begin_trans() Fail(%d)", ret);
1407 case CONTACTS_PERSON_PROPERTY_NAME_CONTACT:
1408 ret = __ctsvc_put_person_default_name(person_id, id); /* contact id */
1410 case CONTACTS_PERSON_PROPERTY_NUMBER:
1411 ret = __ctsvc_put_person_default_data(person_id, id, CTSVC_DATA_NUMBER); /* number id */
1413 case CONTACTS_PERSON_PROPERTY_EMAIL:
1414 ret = __ctsvc_put_person_default_data(person_id, id, CTSVC_DATA_EMAIL); /* email id */
1416 case CONTACTS_PERSON_PROPERTY_IMAGE:
1417 ret = __ctsvc_put_person_default_image(person_id, id); /* image id */
1420 ret = CONTACTS_ERROR_INVALID_PARAMETER;
1423 if (ret < CONTACTS_ERROR_NONE) {
1424 ERR("contacts_person_set_default_property() Fail(%d) : person property (%d)", ret, property);
1425 ctsvc_end_trans(false);
1429 #ifdef _CONTACTS_IPC_SERVER
1430 ctsvc_change_subject_add_changed_person_id(CONTACTS_CHANGE_UPDATED, person_id);
1432 ctsvc_set_person_noti();
1433 ret = ctsvc_end_trans(true);
1438 int ctsvc_person_get_default_property(contacts_person_property_e property, int person_id,
1441 int ret = CONTACTS_ERROR_NONE;
1442 char query[CTS_SQL_MAX_LEN] = {0};
1444 RETVM_IF(person_id <= 0 || id == NULL, CONTACTS_ERROR_INVALID_PARAMETER, "id should be greater than 0");
1448 case CONTACTS_PERSON_PROPERTY_NAME_CONTACT:
1449 snprintf(query, sizeof(query),
1450 "SELECT name_contact_id FROM "CTS_TABLE_PERSONS" WHERE person_id = %d",
1453 case CONTACTS_PERSON_PROPERTY_NUMBER:
1454 snprintf(query, sizeof(query),
1455 "SELECT id FROM "CTS_TABLE_DATA" WHERE is_primary_default = 1 AND datatype = %d AND is_my_profile = 0 AND "
1456 "contact_id in (SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
1457 "WHERE person_id = %d AND deleted = 0)",
1458 CTSVC_DATA_NUMBER, person_id);
1460 case CONTACTS_PERSON_PROPERTY_EMAIL:
1461 snprintf(query, sizeof(query),
1462 "SELECT id FROM "CTS_TABLE_DATA" WHERE is_primary_default = 1 AND datatype = %d AND is_my_profile = 0 AND "
1463 "contact_id in (SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
1464 "WHERE person_id = %d AND deleted = 0)",
1465 CTSVC_DATA_EMAIL, person_id);
1467 case CONTACTS_PERSON_PROPERTY_IMAGE:
1468 snprintf(query, sizeof(query),
1469 "SELECT id FROM "CTS_TABLE_DATA" WHERE is_primary_default = 1 AND datatype = %d AND is_my_profile = 0 AND "
1470 "contact_id in (SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
1471 "WHERE person_id = %d AND deleted = 0)",
1472 CTSVC_DATA_IMAGE, person_id);
1475 ret = CONTACTS_ERROR_INVALID_PARAMETER;
1481 ret = ctsvc_query_get_first_int_result(query, &result);
1482 RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "ctsvc_query_get_first_int_result() Fail(%d)", ret);
1489 static void __ctsvc_collate_numbers(contacts_record_h record, GSList **nums)
1491 int ret = CONTACTS_ERROR_NONE;
1492 GList *cursor = NULL;
1493 ctsvc_contact_s *contact = (ctsvc_contact_s*)record;
1494 ctsvc_number_s *number_data;
1496 if (NULL == contact->numbers) {
1497 DBG("NULL == contact->numbers");
1501 for (cursor = contact->numbers->records; cursor; cursor = cursor->next) {
1502 number_data = cursor->data;
1503 if (number_data && number_data->normalized && number_data->normalized[0]) {
1504 char minmatch[strlen(number_data->normalized) + 1];
1505 ret = ctsvc_get_minmatch_number(number_data->normalized, minmatch, sizeof(minmatch),
1506 ctsvc_get_phonenumber_min_match_digit());
1508 if (CONTACTS_ERROR_NONE != ret)
1511 if (NULL == *nums || NULL == g_slist_find(*nums, minmatch))
1512 *nums = g_slist_append(*nums, strdup(minmatch));
1518 static void __ctsvc_collate_emails(contacts_record_h record, GSList **emails)
1520 GList *cursor = NULL;
1521 ctsvc_contact_s *contact = (ctsvc_contact_s*)record;
1522 ctsvc_email_s *email_data;
1523 int local_part_len = 0;
1524 char local_part[256] = {0};
1526 if (NULL == contact->emails) {
1527 DBG("NULL == contact->emails");
1531 for (cursor = contact->emails->records; cursor; cursor = cursor->next) {
1532 email_data = cursor->data;
1533 if (email_data && email_data->email_addr && email_data->email_addr[0]) {
1534 local_part_len = strcspn(email_data->email_addr, "@");
1535 if (local_part_len <= 0 || strlen(email_data->email_addr) <= local_part_len)
1538 strncpy(local_part, email_data->email_addr, local_part_len + 1);
1540 if (NULL == *emails || NULL == g_slist_find(*emails, local_part))
1541 *emails = g_slist_append(*emails, strdup(local_part));
1546 static void __ctsvc_collate_names(contacts_record_h record, GSList **names)
1548 ctsvc_contact_s *contact = (ctsvc_contact_s*)record;
1549 int comp_name_len = CTSVC_COMP_NAME_LEN;
1550 char comp_name[256] = {0};
1553 if (CONTACTS_DISPLAY_NAME_SOURCE_TYPE_NAME == contact->display_source_type)
1554 name = contact->reverse_sort_name;
1556 if (name && comp_name_len <= strlen(name)) {
1557 if (CTSVC_SORT_KOREAN == contact->display_name_language) { /*compare first name*/
1558 strncpy(comp_name, name + (strlen(name) -comp_name_len),
1560 } else { /*compare last name*/
1561 comp_name_len = strcspn(name, ", ");
1562 strncpy(comp_name, name, comp_name_len);
1565 if (NULL == *names || NULL == g_slist_find(*names, comp_name))
1566 *names = g_slist_append(*names, strdup(comp_name));
1571 static int __ctsvc_get_person_info_by_person_id(int person_id, GSList **nums, GSList **emails, GSList **names)
1573 int ret = CONTACTS_ERROR_NONE;
1574 GSList *contact_ids = NULL;
1575 GSList *cursor = NULL;
1577 char query[CTS_SQL_MIN_LEN] = {0};
1580 snprintf(query, sizeof(query),
1581 "SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
1582 "WHERE deleted = 0 AND person_id = %d", person_id);
1584 ret = ctsvc_query_prepare(query, &stmt);
1585 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1587 while ((ret = ctsvc_stmt_step(stmt))) {
1591 ERR("ctsvc_stmt_step() Fail(%d)", ret);
1592 ctsvc_stmt_finalize(stmt);
1595 contact_id = ctsvc_stmt_get_int(stmt, 0);
1597 contact_ids = g_slist_append(contact_ids, GINT_TO_POINTER(contact_id));
1599 ctsvc_stmt_finalize(stmt);
1601 if (NULL == contact_ids) {
1602 ERR("Fail to get contacts by person_id");
1603 return CONTACTS_ERROR_DB;
1606 for (cursor = contact_ids; cursor; cursor = cursor->next) {
1607 contacts_record_h record = NULL;
1609 int contact_id = GPOINTER_TO_INT(cursor->data);
1610 ret = ctsvc_db_contact_get(contact_id, &record);
1611 if (CONTACTS_ERROR_NONE != ret) {
1612 WARN("ctsvc_db_contact_get() Fail(%d), contact_id = %d", ret, contact_id);
1616 __ctsvc_collate_numbers(record, nums);
1617 __ctsvc_collate_emails(record, emails);
1618 __ctsvc_collate_names(record, names);
1620 contacts_record_destroy(record, true);
1623 g_slist_free(contact_ids);
1628 static void __ctsvc_make_sub_query_by_num(GSList *nums, int person_id,
1629 char **sub_query, int *sub_size, int *sub_len)
1631 GSList *cursor = NULL;
1632 char temp_query[CTS_SQL_MIN_LEN] = {0};
1634 /* Add 2 points whenever a number is matched */
1635 snprintf(temp_query, CTS_SQL_MIN_LEN,
1636 "SELECT C.person_id, 2 score FROM "CTS_TABLE_CONTACTS" C, "CTS_TABLE_DATA" D "
1637 "ON C.contact_id=D.contact_id AND D.datatype=%d AND C.deleted = 0 "
1638 "AND C.person_id <> %d AND D.is_my_profile = 0 "
1639 "WHERE D.data4 = '",
1640 CTSVC_DATA_NUMBER, person_id);
1642 for (cursor = nums; cursor; cursor = cursor->next)
1644 char *minmatch = cursor->data;
1645 if (NULL == minmatch)
1649 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, " UNION ALL ");
1651 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, temp_query);
1652 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, minmatch);
1653 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, "'");
1657 static void __ctsvc_make_sub_query_by_email(GSList *emails, int person_id,
1658 char **sub_query, int *sub_size, int *sub_len)
1660 GSList *cursor = NULL;
1661 char temp_query[CTS_SQL_MIN_LEN] = {0};
1663 /* Add 2 points whenever a email id is matched */
1664 snprintf(temp_query, CTS_SQL_MIN_LEN,
1665 "SELECT C.person_id, 2 score FROM "CTS_TABLE_CONTACTS" C, "CTS_TABLE_DATA" D "
1666 "ON C.contact_id=D.contact_id AND D.datatype=%d AND C.deleted = 0 "
1667 "AND C.person_id <> %d AND D.is_my_profile = 0 "
1668 "WHERE D.data3 LIKE '",
1669 CTSVC_DATA_EMAIL, person_id);
1671 for (cursor = emails; cursor; cursor = cursor->next)
1673 char *local_part = cursor->data;
1674 if (NULL == local_part)
1678 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, " UNION ALL ");
1680 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, temp_query);
1681 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, local_part);
1682 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, "%'");
1686 static void __ctsvc_make_sub_query_by_name(GSList *names, int person_id,
1687 char **sub_query, int *sub_size, int *sub_len)
1689 GSList *cursor = NULL;
1690 char temp_query[CTS_SQL_MIN_LEN] = {0};
1692 /* Add 1 point whenever last name is matched (first name in case of Korean) */
1693 snprintf(temp_query, CTS_SQL_MIN_LEN,
1694 "SELECT person_id, 1 score FROM "CTS_TABLE_CONTACTS" "
1695 "WHERE person_id <> %d AND display_name_source=%d "
1696 "AND reverse_sort_name LIKE '",
1697 person_id, CONTACTS_DISPLAY_NAME_SOURCE_TYPE_NAME);
1699 for (cursor = names; cursor; cursor = cursor->next)
1701 char *name = cursor->data;
1705 int sort_type = ctsvc_get_name_sort_type(name);
1708 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, " UNION ALL ");
1710 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, temp_query);
1711 if (CTSVC_SORT_KOREAN == sort_type) { /*compare first name*/
1712 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, "%");
1713 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, name);
1714 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, "'");
1715 } else { /*compare last name*/
1716 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, name);
1717 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, "%'");
1722 int ctsvc_person_get_aggregation_suggestions(int person_id, int limit, contacts_list_h *out_list)
1724 int ret = CONTACTS_ERROR_NONE;
1728 GSList *nums = NULL;
1729 GSList *emails = NULL;
1730 GSList *names = NULL;
1732 char *sub_query = NULL;
1735 int sub_size = CTS_SQL_MAX_LEN;
1736 contacts_list_h list = NULL;
1737 cts_stmt stmt = NULL;
1739 RETV_IF(person_id <= 0, CONTACTS_ERROR_INVALID_PARAMETER);
1740 RETV_IF(NULL == out_list, CONTACTS_ERROR_INVALID_PARAMETER);
1744 ret = __ctsvc_get_person_info_by_person_id(person_id, &nums, &emails, &names);
1745 if (CONTACTS_ERROR_NONE != ret) {
1746 ERR("__ctsvc_get_person_info_by_person_id() Fail(%d)", ret);
1750 sub_query = calloc(1, sub_size);
1751 if (NULL == sub_query) {
1752 ERR("calloc() Fail");
1753 g_slist_free_full(nums, free);
1754 g_slist_free_full(emails, free);
1755 g_slist_free_full(names, free);
1756 return CONTACTS_ERROR_OUT_OF_MEMORY;
1760 __ctsvc_make_sub_query_by_num(nums, person_id, &sub_query, &sub_size, &sub_len);
1761 g_slist_free_full(nums, free);
1765 __ctsvc_make_sub_query_by_email(emails, person_id, &sub_query, &sub_size, &sub_len);
1766 g_slist_free_full(emails, free);
1770 __ctsvc_make_sub_query_by_name(names, person_id, &sub_query, &sub_size, &sub_len);
1771 g_slist_free_full(names, free);
1777 WARN("no numbers, emails, names for query");
1778 return CONTACTS_ERROR_NO_DATA;
1781 query_size = CTS_SQL_MIN_LEN + sub_len;
1782 query = calloc(1, query_size);
1783 if (NULL == query) {
1784 ERR("calloc() Fail");
1786 return CONTACTS_ERROR_OUT_OF_MEMORY;
1789 snprintf(query, query_size,
1790 "SELECT person_id, sum(score) FROM (%s) "
1791 "GROUP BY person_id ORDER BY score DESC",
1793 ret = ctsvc_query_prepare(query, &stmt);
1795 ERR("ctsvc_query_prepare fail(%d)", ret);
1802 while ((ret = ctsvc_stmt_step(stmt))) {
1804 ERR("ctsvc_stmt_step() Fail(%d)", ret);
1805 ctsvc_stmt_finalize(stmt);
1810 id = ctsvc_stmt_get_int(stmt, 0);
1811 score = ctsvc_stmt_get_int(stmt, 1);
1812 DBG("person_id : %d, score : %d", id, score);
1814 /* Add 2 points whenever a email id or a number is matched */
1815 /* and 1 point whenever some part of name is matched */
1816 /* Aggregation suggestions: the persons who get more than 2 points */
1817 if (CTSVC_AGGREGATION_SUGGESTION_SCORE <= score
1818 && (0 == limit || cnt < limit))
1822 sub_len += snprintf(sub_query + sub_len, sub_size -sub_len, ", %d", id);
1824 sub_len += snprintf(sub_query + sub_len, sub_size -sub_len, "%d", id);
1827 ctsvc_stmt_finalize(stmt);
1832 WARN("no person_id for aggregation suggestions");
1833 return CONTACTS_ERROR_NO_DATA;
1836 snprintf(query, query_size,
1837 "SELECT DISTINCT persons.person_id, "
1839 "_NORMALIZE_INDEX_(%s), "
1841 "persons.image_thumbnail_path, "
1842 "persons.ringtone_path, "
1843 "persons.vibration, "
1844 "persons.message_alert, "
1848 "persons.has_phonenumber, "
1849 "persons.has_email, "
1850 "EXISTS(SELECT person_id FROM "CTS_TABLE_FAVORITES" WHERE person_id=persons.person_id) is_favorite "
1851 "FROM "CTS_TABLE_PERSONS" "
1852 "LEFT JOIN "CTS_TABLE_CONTACTS" "
1853 "ON (name_contact_id = contacts.contact_id AND contacts.deleted = 0) "
1854 "WHERE persons.person_id IN (%s)",
1855 ctsvc_get_display_column(), ctsvc_get_sort_name_column(), sub_query);
1859 ret = ctsvc_query_prepare(query, &stmt);
1862 ERR("ctsvc_query_prepare fail(%d)", ret);
1866 contacts_list_create(&list);
1867 while ((ret = ctsvc_stmt_step(stmt))) {
1868 contacts_record_h record;
1870 ERR("ctsvc_stmt_step() Fail(%d)", ret);
1871 ctsvc_stmt_finalize(stmt);
1872 contacts_list_destroy(list, true);
1875 ret = ctsvc_db_person_create_record_from_stmt(stmt, &record);
1876 if (CONTACTS_ERROR_NONE != ret) {
1877 ERR("ctsvc_db_person_create_record_from_stmt() Fail(%d)", ret);
1878 ctsvc_stmt_finalize(stmt);
1879 contacts_list_destroy(list, true);
1883 ctsvc_list_prepend(list, record);
1885 ctsvc_stmt_finalize(stmt);
1886 ctsvc_list_reverse(list);