fix coding rule violations
[platform/core/pim/contacts-service.git] / server / ctsvc_server_person.c
1 /*
2  * Contacts Service
3  *
4  * Copyright (c) 2010 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
19
20 #include "contacts.h"
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"
35 #include "ctsvc_db_plugin_image_helper.h"
36
37 #ifdef ENABLE_LOG_FEATURE
38 #include "ctsvc_server_phonelog.h"
39 #endif /* ENABLE_LOG_FEATURE */
40
41 #ifdef _CONTACTS_IPC_SERVER
42 #include "ctsvc_server_change_subject.h"
43 #endif
44
45 #define CTSVC_COMP_NAME_LEN 4
46 #define CTSVC_AGGREGATION_SUGGESTION_SCORE 2
47
48 enum {
49         CTSVC_GET_PERSON_DEFAULT_NUMBER_VALUE,
50         CTSVC_GET_PERSON_DEFAULT_EMAIL_VALUE,
51         CTSVC_GET_PERSON_DEFAULT_IMAGE_VALUE,
52 };
53
54 static inline int __ctsvc_get_person_default_number_value(int id, contacts_record_h *record)
55 {
56         int ret;
57         cts_stmt stmt;
58         ctsvc_number_s *number;
59         char query[CTS_SQL_MAX_LEN] = {0};
60
61         snprintf(query, sizeof(query),
62                         "SELECT data.id, data.is_default, data.data1, data.data2, data.data3, data.data4 "
63                         "FROM %s, %s ON data.is_primary_default=1 AND data.datatype=%d "
64                         "AND data.contact_id = contacts.contact_id AND contacts.deleted = 0 "
65                         "WHERE contacts.person_id = %d",
66                         CTS_TABLE_CONTACTS, CTS_TABLE_DATA, CONTACTS_DATA_TYPE_NUMBER, id);
67
68         ret = ctsvc_query_prepare(query, &stmt);
69         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
70
71         ret = ctsvc_stmt_step(stmt);
72         if (1 /*CTS_TRUE*/ != ret) {
73                 /* LCOV_EXCL_START */
74                 ctsvc_stmt_finalize(stmt);
75                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
76                 if (CONTACTS_ERROR_NONE == ret)
77                         return CONTACTS_ERROR_NO_DATA;
78                 else
79                         return ret;
80                 /* LCOV_EXCL_STOP */
81         }
82
83         ret = contacts_record_create(_contacts_number._uri, (contacts_record_h*)&number);
84         if (number) {
85                 char *temp;
86                 number->id = ctsvc_stmt_get_int(stmt, 0);
87                 number->is_default = ctsvc_stmt_get_int(stmt, 1);
88                 number->type = ctsvc_stmt_get_int(stmt, 2);
89                 temp = ctsvc_stmt_get_text(stmt, 3);
90                 number->label = SAFE_STRDUP(temp);
91                 temp = ctsvc_stmt_get_text(stmt, 4);
92                 number->number = SAFE_STRDUP(temp);
93                 temp = ctsvc_stmt_get_text(stmt, 5);
94                 number->lookup = SAFE_STRDUP(temp);
95
96                 *record = (contacts_record_h)number;
97                 ret = CONTACTS_ERROR_NONE;
98         } else {
99                 /* LCOV_EXCL_START */
100                 ERR("contacts_record_create() Fail");
101                 /* LCOV_EXCL_STOP */
102         }
103
104         ctsvc_stmt_finalize(stmt);
105         return ret;
106 }
107
108 static inline int __ctsvc_get_person_default_email_value(int id, contacts_record_h *record)
109 {
110         int ret;
111         cts_stmt stmt;
112         ctsvc_email_s *email;
113         char query[CTS_SQL_MAX_LEN] = {0};
114
115         snprintf(query, sizeof(query),
116                         "SELECT data.id, data.is_default, data.data1, data.data2, data.data3 "
117                         "FROM %s, %s ON data.is_primary_default=1 AND data.datatype=%d "
118                         "AND data.contact_id = contacts.contact_id AND contacts.deleted = 0 "
119                         "WHERE contacts.person_id = %d",
120                         CTS_TABLE_CONTACTS, CTS_TABLE_DATA, CONTACTS_DATA_TYPE_EMAIL, id);
121
122         ret = ctsvc_query_prepare(query, &stmt);
123         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
124
125         ret = ctsvc_stmt_step(stmt);
126         if (1 /*CTS_TRUE*/ != ret) {
127                 /* LCOV_EXCL_START */
128                 ctsvc_stmt_finalize(stmt);
129                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
130                 if (CONTACTS_ERROR_NONE == ret)
131                         return CONTACTS_ERROR_NO_DATA;
132                 else
133                         return ret;
134                 /* LCOV_EXCL_STOP */
135         }
136
137         ret = contacts_record_create(_contacts_email._uri, (contacts_record_h*)&email);
138         if (email) {
139                 char *temp;
140                 email->id = ctsvc_stmt_get_int(stmt, 0);
141                 email->is_default = ctsvc_stmt_get_int(stmt, 1);
142                 email->type = ctsvc_stmt_get_int(stmt, 2);
143                 temp = ctsvc_stmt_get_text(stmt, 3);
144                 email->label = SAFE_STRDUP(temp);
145                 temp = ctsvc_stmt_get_text(stmt, 4);
146                 email->email_addr = SAFE_STRDUP(temp);
147
148                 *record = (contacts_record_h)email;
149                 ret = CONTACTS_ERROR_NONE;
150         } else {
151                 /* LCOV_EXCL_START */
152                 ERR("contacts_record_create() Fail");
153                 /* LCOV_EXCL_STOP */
154         }
155
156         ctsvc_stmt_finalize(stmt);
157         return ret;
158 }
159
160 static inline int __ctsvc_get_person_default_image_value(int id, contacts_record_h *record)
161 {
162         int ret;
163         cts_stmt stmt;
164         ctsvc_image_s *image;
165         char query[CTS_SQL_MAX_LEN] = {0};
166
167         snprintf(query, sizeof(query),
168                         "SELECT data.id, data.is_default, data.data1, data.data2, data.data3 "
169                         "FROM "CTS_TABLE_CONTACTS", "CTS_TABLE_DATA" "
170                         "ON data.is_primary_default=1 AND data.datatype=%d AND data.is_my_profile = 0 "
171                         "AND data.contact_id = contacts.contact_id AND contacts.deleted = 0 "
172                         "WHERE contacts.person_id = %d",
173                         CONTACTS_DATA_TYPE_IMAGE, id);
174
175         ret = ctsvc_query_prepare(query, &stmt);
176         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
177
178         ret = ctsvc_stmt_step(stmt);
179         if (1 /*CTS_TRUE*/ != ret) {
180                 /* LCOV_EXCL_START */
181                 ctsvc_stmt_finalize(stmt);
182                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
183                 if (CONTACTS_ERROR_NONE == ret)
184                         return CONTACTS_ERROR_NO_DATA;
185                 else
186                         return ret;
187                 /* LCOV_EXCL_STOP */
188         }
189
190         ret = contacts_record_create(_contacts_image._uri, (contacts_record_h*)&image);
191         if (image) {
192                 char *temp;
193                 image->id = ctsvc_stmt_get_int(stmt, 0);
194                 image->is_default = ctsvc_stmt_get_int(stmt, 1);
195                 image->type = ctsvc_stmt_get_int(stmt, 2);
196                 temp = ctsvc_stmt_get_text(stmt, 3);
197                 image->label = SAFE_STRDUP(temp);
198                 temp = ctsvc_stmt_get_text(stmt, 4);
199                 image->path = SAFE_STRDUP(temp);
200
201                 *record = (contacts_record_h)image;
202                 ret = CONTACTS_ERROR_NONE;
203         } else {
204                 /* LCOV_EXCL_START */
205                 ERR("contacts_record_create() Fail");
206                 /* LCOV_EXCL_STOP */
207         }
208
209         ctsvc_stmt_finalize(stmt);
210         return ret;
211 }
212
213 static int __ctsvc_get_person_value(int op_code,
214                 int person_id, contacts_record_h *record)
215 {
216         int ret;
217
218         RETV_IF(NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
219
220         switch (op_code) {
221         case CTSVC_GET_PERSON_DEFAULT_NUMBER_VALUE:
222                 ret = __ctsvc_get_person_default_number_value(person_id, record);
223                 RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "__ctsvc_get_person_default_number_value() Fail(%d)", ret);
224                 break;
225         case CTSVC_GET_PERSON_DEFAULT_EMAIL_VALUE:
226                 ret = __ctsvc_get_person_default_email_value(person_id, record);
227                 RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "__ctsvc_get_person_default_email_value() Fail(%d)", ret);
228                 break;
229         case CTSVC_GET_PERSON_DEFAULT_IMAGE_VALUE:
230                 ret = __ctsvc_get_person_default_image_value(person_id, record);
231                 RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "__ctsvc_get_person_default_image_value() Fail(%d)", ret);
232                 break;
233         default:
234                 /* LCOV_EXCL_START */
235                 ERR("The op_code(%d) is not supported", op_code);
236                 return CONTACTS_ERROR_INVALID_PARAMETER;
237                 /* LCOV_EXCL_STOP */
238         }
239
240         if (NULL == *record)
241                 return CONTACTS_ERROR_NO_DATA;
242
243         return ret;
244 }
245
246 static inline int __ctsvc_put_person_default_name(int person_id, int contact_id)
247 {
248         int ret;
249         int id;
250         char query[CTS_SQL_MAX_LEN] = {0};
251
252         snprintf(query, sizeof(query),
253                         "SELECT person_id FROM %s WHERE contact_id=%d AND deleted = 0",
254                         CTS_TABLE_CONTACTS, contact_id);
255
256         ret = ctsvc_query_get_first_int_result(query, &id);
257         RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "ctsvc_query_get_first_int_result() Fail(%d)", ret);
258
259         if (id == person_id) {
260                 ret = ctsvc_begin_trans();
261                 RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_begin_trans() Fail(%d)", ret);
262                 snprintf(query, sizeof(query),
263                                 "UPDATE %s SET name_contact_id=%d WHERE person_id=%d",
264                                 CTS_TABLE_PERSONS, contact_id, person_id);
265
266                 ret = ctsvc_query_exec(query);
267                 if (CONTACTS_ERROR_NONE != ret) {
268                         /* LCOV_EXCL_START */
269                         ERR("ctsvc_query_exec() Fail(%d)", ret);
270                         ctsvc_end_trans(false);
271                         return ret;
272                         /* LCOV_EXCL_STOP */
273                 } else {
274                         ret = ctsvc_end_trans(true);
275                         if (ret < CONTACTS_ERROR_NONE) {
276                                 /* LCOV_EXCL_START */
277                                 ERR("ctsvc_end_trans() Fail(%d)", ret);
278                                 return ret;
279                         } else {
280                                 return CONTACTS_ERROR_NONE;
281                         }
282                         /* LCOV_EXCL_STOP */
283                 }
284         } else {
285                 /* LCOV_EXCL_START */
286                 ERR("contact(%d) does not belong to person(%d), to person(%d)", contact_id, person_id, ret);
287                 ret = CONTACTS_ERROR_NO_DATA;
288                 /* LCOV_EXCL_STOP */
289         }
290
291         return ret;
292 }
293
294 static inline int __ctsvc_put_person_default_image(int person_id, int id)
295 {
296         int ret;
297         int is_default;
298         int contact_id;
299         cts_stmt stmt;
300         char *image_path;
301         char query[CTS_SQL_MAX_LEN] = {0};
302         char *thumbnail_path;
303
304         ret = ctsvc_begin_trans();
305         RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_begin_trans() Fail(%d)", ret);
306
307         snprintf(query, sizeof(query),
308                         "SELECT D.is_default, D.contact_id, D.data3 "
309                         "FROM "CTS_TABLE_DATA" D, "CTS_TABLE_CONTACTS" C "
310                         "ON D.contact_id = C.contact_id AND C.deleted = 0 "
311                         "WHERE D.datatype=%d AND D.is_my_profile = 0 AND C.person_id=%d AND D.id=%d",
312                         CONTACTS_DATA_TYPE_IMAGE, person_id, id);
313         ret = ctsvc_query_prepare(query, &stmt);
314         if (NULL == stmt) {
315                 /* LCOV_EXCL_START */
316                 ERR("ctsvc_query_prepare Fail(%d)", ret);
317                 ctsvc_end_trans(false);
318                 return ret;
319                 /* LCOV_EXCL_STOP */
320         }
321
322         ret = ctsvc_stmt_step(stmt);
323         if (1 != ret) {
324                 /* LCOV_EXCL_START */
325                 ctsvc_stmt_finalize(stmt);
326                 ctsvc_end_trans(false);
327                 return ret;
328                 /* LCOV_EXCL_STOP */
329         }
330
331         is_default = ctsvc_stmt_get_int(stmt, 0);
332         contact_id = ctsvc_stmt_get_int(stmt, 1);
333         image_path = SAFE_STRDUP(ctsvc_stmt_get_text(stmt, 2));
334         ctsvc_stmt_finalize(stmt);
335
336         /* unset is_primary_default of all data of the person */
337         snprintf(query, sizeof(query),
338                         "UPDATE "CTS_TABLE_DATA" SET is_primary_default=0 WHERE datatype=%d AND is_my_profile = 0 "
339                         "AND contact_id IN (SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
340                         "WHERE person_id=%d AND deleted = 0) ",
341                         CONTACTS_DATA_TYPE_IMAGE, person_id);
342         ret = ctsvc_query_exec(query);
343         if (ret < CONTACTS_ERROR_NONE) {
344                 /* LCOV_EXCL_START */
345                 ERR("ctsvc_query_exec() Fail(%d)", ret);
346                 free(image_path);
347                 ctsvc_end_trans(false);
348                 return ret;
349                 /* LCOV_EXCL_STOP */
350         }
351
352         /* unset is_default of all data of person if the data is not default */
353         if (false == is_default) {
354                 snprintf(query, sizeof(query),
355                                 "UPDATE "CTS_TABLE_DATA" SET is_default=0 WHERE datatype=%d  AND is_my_profile = 0 "
356                                 "AND contact_id = %d ", CONTACTS_DATA_TYPE_IMAGE, contact_id);
357
358                 ret = ctsvc_query_exec(query);
359                 if (CONTACTS_ERROR_NONE != ret) {
360                         /* LCOV_EXCL_START */
361                         ERR("ctsvc_query_exec() Fail(%d)", ret);
362                         free(image_path);
363                         ctsvc_end_trans(false);
364                         return ret;
365                         /* LCOV_EXCL_STOP */
366                 }
367
368                 thumbnail_path = ctsvc_utils_make_thumbnail(image_path);
369         } else {
370                 thumbnail_path = ctsvc_utils_get_thumbnail_path(image_path);
371         }
372
373         free(image_path);
374
375         /* set is_default, is _primary_default */
376         snprintf(query, sizeof(query),
377                         "UPDATE "CTS_TABLE_DATA" SET is_primary_default=1, is_default=1 WHERE id=%d ", id);
378         ret = ctsvc_query_exec(query);
379         if (CONTACTS_ERROR_NONE != ret) {
380                 /* LCOV_EXCL_START */
381                 ERR("ctsvc_query_exec() Fail(%d)", ret);
382                 free(thumbnail_path);
383                 ctsvc_end_trans(false);
384                 return ret;
385                 /* LCOV_EXCL_STOP */
386         }
387
388         /* update person's image_thumbnail_path */
389         snprintf(query, sizeof(query),
390                         "UPDATE "CTS_TABLE_PERSONS" SET image_thumbnail_path=? WHERE person_id=%d ", person_id);
391         ret = ctsvc_query_prepare(query, &stmt);
392         if (NULL == stmt) {
393                 /* LCOV_EXCL_START */
394                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
395                 free(thumbnail_path);
396                 ctsvc_end_trans(false);
397                 return ret;
398                 /* LCOV_EXCL_STOP */
399         }
400
401         ctsvc_stmt_bind_text(stmt, 1, thumbnail_path);
402         ret = ctsvc_stmt_step(stmt);
403         if (CONTACTS_ERROR_NONE != ret) {
404                 /* LCOV_EXCL_START */
405                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
406                 ctsvc_stmt_finalize(stmt);
407                 free(thumbnail_path);
408                 ctsvc_end_trans(false);
409                 return ret;
410                 /* LCOV_EXCL_STOP */
411         }
412         ctsvc_stmt_finalize(stmt);
413
414         /* update contact's image_thumbnail_path */
415         if (false == is_default) {
416                 snprintf(query, sizeof(query),
417                                 "UPDATE "CTS_TABLE_CONTACTS" SET image_thumbnail_path=? WHERE contact_id=%d ", contact_id);
418                 ret = ctsvc_query_prepare(query, &stmt);
419                 if (NULL == stmt) {
420                         /* LCOV_EXCL_START */
421                         ERR("ctsvc_query_prepare() Fail(%d)", ret);
422                         free(thumbnail_path);
423                         ctsvc_end_trans(false);
424                         return ret;
425                         /* LCOV_EXCL_STOP */
426                 }
427
428                 ctsvc_stmt_bind_text(stmt, 1, thumbnail_path);
429                 ret = ctsvc_stmt_step(stmt);
430                 if (CONTACTS_ERROR_NONE != ret) {
431                         /* LCOV_EXCL_START */
432                         ERR("ctsvc_stmt_step() Fail(%d)", ret);
433                         ctsvc_stmt_finalize(stmt);
434                         free(thumbnail_path);
435                         ctsvc_end_trans(false);
436                         return ret;
437                         /* LCOV_EXCL_STOP */
438                 }
439                 ctsvc_stmt_finalize(stmt);
440         }
441
442         free(thumbnail_path);
443
444         ret = ctsvc_end_trans(true);
445         return ret;
446 }
447
448 static inline int __ctsvc_put_person_default_data(int person_id, int id, int datatype)
449 {
450         int ret;
451         int is_default = 0;
452         int contact_id = 0;
453         int name_contact_id = 0;
454         char query[CTS_SQL_MAX_LEN] = {0};
455         cts_stmt stmt = NULL;
456         contacts_display_name_source_type_e source_type = CONTACTS_DISPLAY_NAME_SOURCE_TYPE_INVALID;
457
458         snprintf(query, sizeof(query),
459                         "SELECT D.is_default, D.contact_id FROM %s D, %s C "
460                         "ON (D.contact_id=C.contact_id AND C.deleted = 0) "
461                         "WHERE D.datatype=%d AND C.person_id=%d AND D.id=%d",
462                         CTS_TABLE_DATA, CTS_TABLE_CONTACTS, datatype, person_id, id);
463
464         ret = ctsvc_query_prepare(query, &stmt);
465         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
466
467         ret = ctsvc_stmt_step(stmt);
468         if (1 != ret) {
469                 /* LCOV_EXCL_START */
470                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
471                 ctsvc_stmt_finalize(stmt);
472                 return ret;
473                 /* LCOV_EXCL_STOP */
474         }
475
476         is_default = ctsvc_stmt_get_int(stmt, 0);
477         contact_id = ctsvc_stmt_get_int(stmt, 1);
478
479         ctsvc_stmt_finalize(stmt);
480
481         ret = ctsvc_begin_trans();
482         RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_begin_trans() Fail(%d)", ret);
483
484         /* unset is_primary_default of all data of the person */
485         snprintf(query, sizeof(query),
486                         "UPDATE "CTS_TABLE_DATA" SET is_primary_default=0 WHERE datatype=%d AND is_my_profile = 0 "
487                         "AND contact_id IN (SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
488                         "WHERE person_id=%d AND deleted = 0) ",
489                         datatype, person_id);
490
491         ret = ctsvc_query_exec(query);
492         if (ret < CONTACTS_ERROR_NONE) {
493                 /* LCOV_EXCL_START */
494                 ERR("ctsvc_query_exec() Fail(%d)", ret);
495                 ctsvc_end_trans(false);
496                 return ret;
497                 /* LCOV_EXCL_STOP */
498         }
499
500         /* unset is_default of all data of person if the data is not default */
501         if (false == is_default) {
502                 snprintf(query, sizeof(query),
503                                 "UPDATE "CTS_TABLE_DATA" SET is_default=0 WHERE datatype=%d AND is_my_profile = 0 "
504                                 "AND contact_id = (SELECT contact_id FROM "CTS_TABLE_DATA" WHERE id=%d) ",
505                                 datatype, id);
506
507                 ret = ctsvc_query_exec(query);
508                 if (CONTACTS_ERROR_NONE != ret) {
509                         /* LCOV_EXCL_START */
510                         ERR("ctsvc_query_exec() Fail(%d)", ret);
511                         ctsvc_end_trans(false);
512                         return ret;
513                         /* LCOV_EXCL_STOP */
514                 }
515         }
516
517         /* set is_default, is _primary_default */
518         snprintf(query, sizeof(query),
519                         "UPDATE "CTS_TABLE_DATA" SET is_primary_default=1, is_default=1 WHERE id=%d ", id);
520
521         ret = ctsvc_query_exec(query);
522         if (CONTACTS_ERROR_NONE != ret) {
523                 /* LCOV_EXCL_START */
524                 ERR("ctsvc_query_exec() Fail(%d)", ret);
525                 ctsvc_end_trans(false);
526                 return ret;
527                 /* LCOV_EXCL_STOP */
528         }
529
530         if (datatype == CONTACTS_DATA_TYPE_NUMBER)
531                 source_type = CONTACTS_DISPLAY_NAME_SOURCE_TYPE_NUMBER;
532         else if (datatype == CONTACTS_DATA_TYPE_EMAIL)
533                 source_type = CONTACTS_DISPLAY_NAME_SOURCE_TYPE_EMAIL;
534
535         if (CONTACTS_DISPLAY_NAME_SOURCE_TYPE_INVALID != source_type)
536                 ctsvc_contact_update_display_name(contact_id, source_type);
537
538         snprintf(query, sizeof(query),
539                         "SELECT name_contact_id FROM "CTS_TABLE_PERSONS" WHERE person_id = %d", person_id);
540         ret = ctsvc_query_get_first_int_result(query, &name_contact_id);
541         if (CONTACTS_ERROR_NONE != ret) {
542                 /* LCOV_EXCL_START */
543                 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
544                 ctsvc_end_trans(false);
545                 return ret;
546                 /* LCOV_EXCL_STOP */
547         }
548
549         if (name_contact_id != contact_id) {
550                 int org_source_type = CONTACTS_DISPLAY_NAME_SOURCE_TYPE_INVALID;
551                 snprintf(query, sizeof(query),
552                                 "SELECT display_name_source FROM "CTS_TABLE_CONTACTS" WHERE contact_id = %d", name_contact_id);
553                 ret = ctsvc_query_get_first_int_result(query, &org_source_type);
554                 if (CONTACTS_ERROR_NONE != ret) {
555                         /* LCOV_EXCL_START */
556                         ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
557                         ctsvc_end_trans(false);
558                         return ret;
559                         /* LCOV_EXCL_STOP */
560                 }
561
562                 if (org_source_type <= source_type) {
563                         snprintf(query, sizeof(query),
564                                         "UPDATE %s SET name_contact_id=%d WHERE person_id=%d",
565                                         CTS_TABLE_PERSONS, contact_id, person_id);
566                         ret = ctsvc_query_exec(query);
567                         if (CONTACTS_ERROR_NONE != ret) {
568                                 /* LCOV_EXCL_START */
569                                 ERR("ctsvc_query_exec() Fail(%d)", ret);
570                                 ctsvc_end_trans(false);
571                                 return ret;
572                                 /* LCOV_EXCL_STOP */
573                         }
574                 }
575         }
576
577         ret = ctsvc_end_trans(true);
578         if (ret < CONTACTS_ERROR_NONE) {
579                 /* LCOV_EXCL_START */
580                 ERR("ctsvc_end_trans() Fail(%d)", ret);
581                 return ret;
582                 /* LCOV_EXCL_STOP */
583         } else {
584                 return CONTACTS_ERROR_NONE;
585         }
586 }
587
588 void ctsvc_db_person_delete_callback(sqlite3_context  *context,
589                 int argc, sqlite3_value **argv)
590 {
591 #ifdef _CONTACTS_IPC_SERVER
592         int person_id;
593
594         if (argc < 1) {
595                 sqlite3_result_null(context);
596                 return;
597         }
598
599         person_id = sqlite3_value_int(argv[0]);
600         ctsvc_change_subject_add_changed_person_id(CONTACTS_CHANGE_DELETED, person_id);
601
602 #ifdef ENABLE_LOG_FEATURE
603         /*
604          * update phonelog
605          * CASE : do not know the proper new person_id
606          */
607         ctsvc_db_phone_log_update_person_id(NULL, person_id, -1, false, NULL);
608 #endif /* ENABLE_LOG_FEATURE */
609         sqlite3_result_null(context);
610         return;
611 #endif
612 }
613
614 int ctsvc_person_aggregate(int person_id)
615 {
616         int ret, len = 0;
617         int version;
618         int link_count;
619         int id = 0;
620         char *addressbook_ids = NULL;
621         int addressbooks_len = 100;
622         int name_contact_id = 0;
623         int person_name_contact_id = 0;
624         int display_name_source_type = CONTACTS_DISPLAY_NAME_SOURCE_TYPE_INVALID;
625         char query[CTS_SQL_MIN_LEN] = {0};
626         char *ringtone_path = NULL;
627         char *image_thumbnail_path = NULL;
628         char *vibration = NULL;
629         char *message_alert = NULL;
630         char *status = NULL;
631         const char *temp;
632         cts_stmt stmt;
633         ctsvc_person_s *person;
634         bool person_is_favorite = false;
635
636         /*
637          * person aggregation : person link/unlink, contact insert (auto link),
638          *  contact delete, garbage collection (addressbook delete)
639          * It should be get all contacts of person regardless of permission
640          * Get person info directly instead of contacts_db_get_record(_contacts_person._uri, person_id, (contacts_record_h*)&person);
641          */
642         snprintf(query, sizeof(query),
643                         "SELECT person_id, "
644                         "name_contact_id, "
645                         "image_thumbnail_path, "
646                         "ringtone_path, "
647                         "vibration, "
648                         "message_alert "
649                         "FROM "CTS_TABLE_PERSONS" "
650                         "WHERE persons.person_id = %d", person_id);
651         ret = ctsvc_query_prepare(query, &stmt);
652         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
653
654         if (1 != ctsvc_stmt_step(stmt)) {
655                 /* LCOV_EXCL_START */
656                 ERR("ctsvc_stmt_step() Fail\n");
657                 return CONTACTS_ERROR_DB;
658                 /* LCOV_EXCL_STOP */
659         }
660         ret = contacts_record_create(_contacts_person._uri, (contacts_record_h*)&person);
661         if (CONTACTS_ERROR_NONE != ret) {
662                 /* LCOV_EXCL_START */
663                 ERR("contacts_record_create() Fail\n");
664                 return CONTACTS_ERROR_INTERNAL;
665                 /* LCOV_EXCL_STOP */
666         }
667         person->person_id = ctsvc_stmt_get_int(stmt, 0);
668         person->name_contact_id = ctsvc_stmt_get_int(stmt, 1);
669         temp = ctsvc_stmt_get_text(stmt, 2);
670         person->image_thumbnail_path = SAFE_STRDUP(temp);
671         temp = ctsvc_stmt_get_text(stmt, 3);
672         person->ringtone_path = SAFE_STRDUP(temp);
673         temp = ctsvc_stmt_get_text(stmt, 4);
674         person->vibration = SAFE_STRDUP(temp);
675         temp = ctsvc_stmt_get_text(stmt, 5);
676         person->message_alert = SAFE_STRDUP(temp);
677         ctsvc_stmt_finalize(stmt);
678
679         /* check image_thumbnail_path */
680         if (person->image_thumbnail_path) {
681                 char *image_path = NULL;
682
683                 image_path = ctsvc_utils_get_image_path(person->image_thumbnail_path);
684                 snprintf(query, sizeof(query),
685                                 "SELECT D.id FROM "CTS_TABLE_CONTACTS" C, "CTS_TABLE_DATA" D "
686                                 "WHERE C.person_id=%d AND C.contact_id=D.contact_id AND C.deleted = 0 "
687                                 "AND D.datatype=%d AND D.is_primary_default = 1 AND D.data3='%s'",
688                                 person->person_id, CONTACTS_DATA_TYPE_IMAGE, image_path);
689                 free(image_path);
690                 ret = ctsvc_query_get_first_int_result(query, &id);
691                 if (ret == CONTACTS_ERROR_NONE)
692                         image_thumbnail_path = SAFE_STRDUP(person->image_thumbnail_path);
693         }
694
695         /* check name_contact_id */
696         snprintf(query, sizeof(query),
697                         "SELECT contact_id FROM %s "
698                         "WHERE person_id=%d AND contact_id=%d AND deleted = 0",
699                         CTS_TABLE_CONTACTS, person->person_id, person->name_contact_id);
700
701         ret = ctsvc_query_get_first_int_result(query, &id);
702         if (ret == CONTACTS_ERROR_NONE) {
703                 name_contact_id = person->name_contact_id;
704                 person_name_contact_id = person->name_contact_id;
705         } else {
706                 name_contact_id = 0;
707                 person_name_contact_id = 0;
708         }
709
710         /* get status of person */
711         snprintf(query, sizeof(query),
712                         "SELECT a.status FROM %s c, %s a "
713                         "ON c.contact_id = a.contact_id AND c.deleted = 0 "
714                         "WHERE c.person_id=%d "
715                         "ORDER BY timestamp DESC LIMIT 1",
716                         CTS_TABLE_CONTACTS, CTS_TABLE_ACTIVITIES, person->person_id);
717         ret = ctsvc_query_prepare(query, &stmt);
718         if (NULL == stmt) {
719                 /* LCOV_EXCL_START */
720                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
721                 free(image_thumbnail_path);
722                 contacts_record_destroy((contacts_record_h)person, true);
723                 return ret;
724                 /* LCOV_EXCL_STOP */
725         }
726
727         if (1 == ctsvc_stmt_step(stmt)) {
728                 temp = ctsvc_stmt_get_text(stmt, 0);
729                 status = SAFE_STRDUP(temp);
730         }
731         ctsvc_stmt_finalize(stmt);
732
733         /* check ringtone_path */
734         if (person->ringtone_path) {
735                 snprintf(query, sizeof(query),
736                                 "SELECT C.contact_id FROM "CTS_TABLE_CONTACTS" C "
737                                 "WHERE C.person_id=%d AND C.deleted = 0 "
738                                 "AND C.ringtone_path = '%s'",
739                                 person->person_id, person->ringtone_path);
740                 ret = ctsvc_query_get_first_int_result(query, &id);
741                 if (ret == CONTACTS_ERROR_NONE)
742                         ringtone_path = SAFE_STRDUP(person->ringtone_path);
743         } else {
744                 ringtone_path = NULL;
745         }
746
747         /* check vibration */
748         if (person->vibration) {
749                 snprintf(query, sizeof(query),
750                                 "SELECT C.contact_idFROM "CTS_TABLE_CONTACTS" C "
751                                 "WHERE C.person_id=%d AND C.deleted = 0 "
752                                 "AND C.vibration = '%s'",
753                                 person->person_id, person->vibration);
754                 ret = ctsvc_query_get_first_int_result(query, &id);
755                 if (ret == CONTACTS_ERROR_NONE)
756                         vibration = SAFE_STRDUP(person->vibration);
757         } else {
758                 vibration = NULL;
759         }
760
761         /* check vibration */
762         if (person->message_alert) {
763                 snprintf(query, sizeof(query),
764                                 "SELECT C.contact_id FROM "CTS_TABLE_CONTACTS" C "
765                                 "WHERE C.person_id=%d AND C.deleted = 0 "
766                                 "AND C.message_alert = '%s'",
767                                 person->person_id, person->message_alert);
768                 ret = ctsvc_query_get_first_int_result(query, &id);
769                 if (ret == CONTACTS_ERROR_NONE)
770                         message_alert = SAFE_STRDUP(person->message_alert);
771         } else {
772                 message_alert = NULL;
773         }
774         contacts_record_destroy((contacts_record_h)person, true);
775
776         snprintf(query, sizeof(query),
777                         "SELECT contact_id, contacts.addressbook_id, display_name_source, "
778                         "image_thumbnail_path, ringtone_path, vibration, message_alert, is_favorite "
779                         "FROM %s "
780                         "WHERE person_id = %d AND contacts.deleted = 0 "
781                         "ORDER BY contact_id",
782                         CTS_TABLE_CONTACTS, person_id);
783         ret = ctsvc_query_prepare(query, &stmt);
784         if (NULL == stmt) {
785                 /* LCOV_EXCL_START */
786                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
787                 free(image_thumbnail_path);
788                 free(ringtone_path);
789                 free(vibration);
790                 free(message_alert);
791                 free(status);
792                 return ret;
793                 /* LCOV_EXCL_STOP */
794         }
795
796         link_count = 0;
797         len = 0;
798         while ((ret = ctsvc_stmt_step(stmt))) {
799                 const char *temp_str;
800                 int i = 0;
801                 int contact_id;
802                 int addressbook_id;
803                 int contact_display_name_source_type = CONTACTS_DISPLAY_NAME_SOURCE_TYPE_INVALID;
804                 char *contact_ringtone_path = NULL;
805                 char *contact_image_thumbnail_path = NULL;
806                 char *contact_vibration = NULL;
807                 char *contact_message_alert = NULL;
808                 bool is_favorite = false;
809                 char addr[10] = {0};
810                 int addr_len = 0;
811
812                 contact_id = ctsvc_stmt_get_int(stmt, i++);
813                 addressbook_id = ctsvc_stmt_get_int(stmt, i++);
814                 contact_display_name_source_type = ctsvc_stmt_get_int(stmt, i++);
815                 temp = ctsvc_stmt_get_text(stmt, i++);
816                 if (temp)
817                         contact_image_thumbnail_path = strdup(temp);
818                 temp = ctsvc_stmt_get_text(stmt, i++);
819                 contact_ringtone_path = SAFE_STRDUP(temp);
820                 temp = ctsvc_stmt_get_text(stmt, i++);
821                 contact_vibration = SAFE_STRDUP(temp);
822                 temp = ctsvc_stmt_get_text(stmt, i++);
823                 contact_message_alert = SAFE_STRDUP(temp);
824                 is_favorite = ctsvc_stmt_get_int(stmt, i++);
825
826                 link_count++;
827
828                 if (display_name_source_type < contact_display_name_source_type) {
829                         display_name_source_type = contact_display_name_source_type;
830                         name_contact_id = contact_id;
831                 } else if (contact_display_name_source_type == display_name_source_type) {
832                         if (name_contact_id != person_name_contact_id && person_name_contact_id != 0)
833                                 name_contact_id = person_name_contact_id;
834                         else if (person_name_contact_id == 0 && name_contact_id == 0)
835                                 name_contact_id = contact_id;
836                 }
837
838                 addr_len = snprintf(addr, sizeof(addr), "%d%s", addressbook_id, ADDRESSBOOK_ID_DELIM);
839                 if (NULL == addressbook_ids) {
840                         addressbook_ids = calloc(addressbooks_len + 1, sizeof(char));
841                         if (NULL == addressbook_ids)
842                                 ERR("alloc() failed");
843                 } else if (addressbooks_len <= strlen(addressbook_ids) + addr_len) {
844                         int new_addressbooks_len = MAX(addressbooks_len * 2, strlen(addressbook_ids) + addr_len + 1);
845                         char *new_addressbook_ids = realloc(addressbook_ids, new_addressbooks_len);
846                         if (new_addressbook_ids) {
847                                 addressbook_ids = new_addressbook_ids;
848                                 addressbooks_len = new_addressbooks_len;
849                         } else {
850                                 ERR("realloc() failed");
851                         }
852                 }
853
854                 if (addressbook_ids && addressbooks_len - len > addr_len)
855                         len += snprintf(addressbook_ids + len, addressbooks_len - len, "%d%s", addressbook_id, ADDRESSBOOK_ID_DELIM);
856
857                 if (NULL == image_thumbnail_path && contact_image_thumbnail_path && *contact_image_thumbnail_path) {
858                         image_thumbnail_path = SAFE_STRDUP(contact_image_thumbnail_path);
859
860                         /*update data table : is_primary_default */
861                         ctsvc_db_image_set_primary_default(contact_id, image_thumbnail_path, true);
862                 }
863                 free(contact_image_thumbnail_path);
864
865                 temp_str = contact_ringtone_path;
866                 if (NULL == ringtone_path && temp_str && strlen(temp_str))
867                         ringtone_path = SAFE_STRDUP(temp_str);
868                 free(contact_ringtone_path);
869
870                 temp_str = contact_vibration;
871                 if (NULL == vibration && temp_str && strlen(temp_str))
872                         vibration = SAFE_STRDUP(temp_str);
873                 free(contact_vibration);
874
875                 temp_str = contact_message_alert;
876                 if (NULL == message_alert && temp_str && strlen(temp_str))
877                         message_alert = SAFE_STRDUP(temp_str);
878                 free(contact_message_alert);
879
880                 if (is_favorite)
881                         person_is_favorite = true;
882         }
883         ctsvc_stmt_finalize(stmt);
884         version = ctsvc_get_next_ver();
885
886         snprintf(query, sizeof(query),
887                         "UPDATE "CTS_TABLE_PERSONS" SET dirty=0, name_contact_id = %d, changed_ver = %d, "
888                         "has_phonenumber = EXISTS(SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
889                         "WHERE person_id = %d AND has_phonenumber = 1 AND deleted = 0), "
890                         "has_email = EXISTS(SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
891                         "WHERE person_id = %d AND has_email = 1 AND deleted = 0), "
892                         "link_count = %d, addressbook_ids = ?, ringtone_path=?, vibration=?, message_alert=?, status=?, image_thumbnail_path=? "
893                         "WHERE person_id = %d ",
894                         name_contact_id, version, person_id,
895                         person_id, link_count, person_id);
896
897         ret = ctsvc_query_prepare(query, &stmt);
898         if (NULL == stmt) {
899                 /* LCOV_EXCL_START */
900                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
901                 free(addressbook_ids);
902                 free(image_thumbnail_path);
903                 free(ringtone_path);
904                 free(vibration);
905                 free(message_alert);
906                 free(status);
907                 return ret;
908                 /* LCOV_EXCL_STOP */
909         }
910
911         if (addressbook_ids)
912                 ctsvc_stmt_bind_text(stmt, 1, addressbook_ids);
913         if (ringtone_path)
914                 ctsvc_stmt_bind_text(stmt, 2, ringtone_path);
915         if (vibration)
916                 ctsvc_stmt_bind_text(stmt, 3, vibration);
917         if (message_alert)
918                 ctsvc_stmt_bind_text(stmt, 4, message_alert);
919         if (status)
920                 ctsvc_stmt_bind_text(stmt, 5, status);
921         if (image_thumbnail_path)
922                 ctsvc_stmt_bind_text(stmt, 6, image_thumbnail_path);
923
924         ret = ctsvc_stmt_step(stmt);
925         if (CONTACTS_ERROR_NONE != ret) {
926                 /* LCOV_EXCL_START */
927                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
928                 ctsvc_stmt_finalize(stmt);
929                 free(addressbook_ids);
930                 free(image_thumbnail_path);
931                 free(ringtone_path);
932                 free(vibration);
933                 free(message_alert);
934                 free(status);
935                 return ret;
936                 /* LCOV_EXCL_STOP */
937         }
938
939         ctsvc_stmt_finalize(stmt);
940
941         free(addressbook_ids);
942         free(image_thumbnail_path);
943         free(ringtone_path);
944         free(vibration);
945         free(message_alert);
946         free(status);
947
948         if (false == person_is_favorite) {
949                 snprintf(query, sizeof(query),
950                                 "DELETE FROM "CTS_TABLE_FAVORITES" WHERE person_id = %d", person_id);
951                 ret = ctsvc_query_exec(query);
952                 if (CONTACTS_ERROR_NONE != ret) {
953                         /* LCOV_EXCL_START */
954                         ERR("ctsvc_query_exec() Fail(%d)", ret);
955                         return ret;
956                         /* LCOV_EXCL_STOP */
957                 }
958         }
959
960         ctsvc_set_person_noti();
961 #ifdef _CONTACTS_IPC_SERVER
962         ctsvc_change_subject_add_changed_person_id(CONTACTS_CHANGE_UPDATED, person_id);
963 #endif
964
965         return CONTACTS_ERROR_NONE;
966 }
967
968 static bool __ctsvc_get_person_favorite_info(int person_id, double *priority)
969 {
970         int ret;
971         cts_stmt stmt;
972         char query[CTS_SQL_MIN_LEN] = {0};
973         snprintf(query, sizeof(query),
974                         "SELECT favorite_prio FROM "CTS_TABLE_FAVORITES" WHERE person_id = %d", person_id);
975         ret = ctsvc_query_prepare(query, &stmt);
976         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
977
978         ret = ctsvc_stmt_step(stmt);
979         if (1 == ret) {
980                 *priority = ctsvc_stmt_get_dbl(stmt, 0);
981                 ctsvc_stmt_finalize(stmt);
982                 return true;
983         }
984         ctsvc_stmt_finalize(stmt);
985         return false;
986 }
987
988 int ctsvc_person_link_person(int base_person_id, int person_id)
989 {
990         int ret;
991         char query[CTS_SQL_MIN_LEN] = {0};
992         int default_number_id = 0;
993         int default_email_id = 0;
994         int default_image_id = 0;
995         contacts_record_h record = NULL;
996         bool base_is_favorite = false;
997         bool is_favorite = false;
998         double favorite_prio = 0.0;
999
1000         RETVM_IF(base_person_id == person_id, CONTACTS_ERROR_INVALID_PARAMETER,
1001                         "base_person_id(%d), person_id(%d)", base_person_id, person_id);
1002
1003         ret = ctsvc_begin_trans();
1004         RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_begin_trans() Fail(%d)", ret);
1005
1006         ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_NUMBER_VALUE, base_person_id, &record);
1007         if (CONTACTS_ERROR_NONE != ret) {
1008                 ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_NUMBER_VALUE, person_id, &record);
1009                 if (CONTACTS_ERROR_NONE == ret) {
1010                         contacts_record_get_int(record, CTSVC_PROPERTY_NUMBER_ID, &default_number_id);
1011                         contacts_record_destroy(record, true);
1012                 }
1013         } else {
1014                 contacts_record_get_int(record, CTSVC_PROPERTY_NUMBER_ID, &default_number_id);
1015                 contacts_record_destroy(record, true);
1016         }
1017
1018         ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_EMAIL_VALUE, base_person_id, &record);
1019         if (CONTACTS_ERROR_NONE != ret) {
1020                 ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_EMAIL_VALUE, person_id, &record);
1021                 if (CONTACTS_ERROR_NONE == ret) {
1022                         contacts_record_get_int(record, CTSVC_PROPERTY_EMAIL_ID, &default_email_id);
1023                         contacts_record_destroy(record, true);
1024                 }
1025         } else {
1026                 contacts_record_get_int(record, CTSVC_PROPERTY_EMAIL_ID, &default_email_id);
1027                 contacts_record_destroy(record, true);
1028         }
1029
1030         ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_IMAGE_VALUE, base_person_id, &record);
1031         if (CONTACTS_ERROR_NONE != ret) {
1032                 ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_IMAGE_VALUE, person_id, &record);
1033                 if (CONTACTS_ERROR_NONE == ret) {
1034                         contacts_record_get_int(record, CTSVC_PROPERTY_IMAGE_ID, &default_image_id);
1035                         contacts_record_destroy(record, true);
1036                 }
1037         } else {
1038                 contacts_record_get_int(record, CTSVC_PROPERTY_IMAGE_ID, &default_image_id);
1039                 contacts_record_destroy(record, true);
1040         }
1041
1042         base_is_favorite = __ctsvc_get_person_favorite_info(base_person_id, &favorite_prio);
1043         if (false == base_is_favorite)
1044                 is_favorite = __ctsvc_get_person_favorite_info(person_id, &favorite_prio);
1045
1046         snprintf(query, sizeof(query),
1047                         "UPDATE %s SET person_id = %d WHERE person_id = %d AND deleted = 0",
1048                         CTS_TABLE_CONTACTS, base_person_id, person_id);
1049         ret = ctsvc_query_exec(query);
1050         if (CONTACTS_ERROR_NONE != ret) {
1051                 /* LCOV_EXCL_START */
1052                 ERR("ctsvc_query_exec() Fail(%d)", ret);
1053                 ctsvc_end_trans(false);
1054                 return ret;
1055                 /* LCOV_EXCL_STOP */
1056         }
1057
1058         ctsvc_person_aggregate(base_person_id);
1059
1060         if (default_number_id)
1061                 __ctsvc_put_person_default_data(base_person_id, default_number_id, CONTACTS_DATA_TYPE_NUMBER);
1062
1063         if (default_email_id)
1064                 __ctsvc_put_person_default_data(base_person_id, default_email_id, CONTACTS_DATA_TYPE_EMAIL);
1065
1066         if (default_image_id)
1067                 __ctsvc_put_person_default_image(base_person_id, default_image_id);
1068
1069 #ifdef ENABLE_LOG_FEATURE
1070         /*
1071          * update phonelog
1072          * Updating phonelog person_id before deleting person
1073          * Because, when deleting, ctsvc_db_person_delete_callback will be called
1074          * the logic takes more time to find proper person_id (base_person_id)
1075          */
1076         ctsvc_db_phone_log_update_person_id(NULL, person_id, base_person_id, true, NULL);
1077 #endif /* ENABLE_LOG_FEATURE */
1078
1079         snprintf(query, sizeof(query), "DELETE FROM %s WHERE person_id = %d",
1080                         CTS_TABLE_PERSONS, person_id);
1081         ret = ctsvc_query_exec(query);
1082         if (CONTACTS_ERROR_NONE != ret) {
1083                 /* LCOV_EXCL_START */
1084                 ERR("ctsvc_query_exec() Fail(%d)", ret);
1085                 ctsvc_end_trans(false);
1086                 return ret;
1087                 /* LCOV_EXCL_STOP */
1088         }
1089         /*
1090          *#ifdef _CONTACTS_IPC_SERVER
1091          *  It will be added in ctsvc_db_person_delete_callback
1092          *  ctsvc_change_subject_add_changed_person_id(CONTACTS_CHANGE_DELETED, person_id);
1093          *#endif
1094          */
1095
1096         if (is_favorite) {
1097                 snprintf(query, sizeof(query),
1098                                 "INSERT INTO "CTS_TABLE_FAVORITES" values(%d, %f)", base_person_id, favorite_prio);
1099                 ret = ctsvc_query_exec(query);
1100                 if (CONTACTS_ERROR_NONE != ret) {
1101                         /* LCOV_EXCL_START */
1102                         ERR("ctsvc_query_exec() Fail(%d)", ret);
1103                         ctsvc_end_trans(false);
1104                         return ret;
1105                         /* LCOV_EXCL_STOP */
1106                 }
1107         }
1108
1109         ctsvc_set_person_noti();
1110         ret = ctsvc_end_trans(true);
1111         if (ret < CONTACTS_ERROR_NONE) {
1112                 /* LCOV_EXCL_START */
1113                 ERR("ctsvc_end_trans() Fail(%d)", ret);
1114                 return ret;
1115                 /* LCOV_EXCL_STOP */
1116         } else {
1117                 return CONTACTS_ERROR_NONE;
1118         }
1119 }
1120
1121 static int __ctsvc_update_primary_default_data(int person_id)
1122 {
1123         int ret;
1124         contacts_record_h record = NULL;
1125         char query[CTS_SQL_MIN_LEN] = {0};
1126         cts_stmt stmt;
1127
1128         ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_NUMBER_VALUE, person_id, &record);
1129         if (CONTACTS_ERROR_NONE != ret) {
1130                 snprintf(query, sizeof(query),
1131                                 "SELECT contact_id "
1132                                 "FROM %s "
1133                                 "WHERE person_id = %d AND deleted = 0 "
1134                                 "ORDER BY contact_id",
1135                                 CTS_TABLE_CONTACTS, person_id);
1136                 ret = ctsvc_query_prepare(query, &stmt);
1137                 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1138
1139                 while (1 == ctsvc_stmt_step(stmt)) {
1140                         int contact_id = ctsvc_stmt_get_int(stmt, 0);
1141                         cts_stmt stmt_number;
1142
1143                         snprintf(query, sizeof(query),
1144                                         "SELECT id, is_default FROM %s "
1145                                         "WHERE contact_id = %d AND datatype = %d AND is_default = 1 AND is_my_profile = 0",
1146                                         CTS_TABLE_DATA, contact_id, CONTACTS_DATA_TYPE_NUMBER);
1147
1148                         ret = ctsvc_query_prepare(query, &stmt_number);
1149                         if (NULL == stmt_number) {
1150                                 /* LCOV_EXCL_START */
1151                                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
1152                                 ctsvc_stmt_finalize(stmt);
1153                                 return ret;
1154                                 /* LCOV_EXCL_STOP */
1155                         }
1156
1157                         if (1 == ctsvc_stmt_step(stmt_number)) {
1158                                 int default_number_id = ctsvc_stmt_get_int(stmt_number, 0);
1159                                 __ctsvc_put_person_default_data(person_id, default_number_id, CONTACTS_DATA_TYPE_NUMBER);
1160                                 ctsvc_stmt_finalize(stmt_number);
1161                                 break;
1162                         }
1163                         ctsvc_stmt_finalize(stmt_number);
1164                 }
1165                 ctsvc_stmt_finalize(stmt);
1166         } else {
1167                 contacts_record_destroy(record, true);
1168         }
1169
1170         ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_EMAIL_VALUE, person_id, &record);
1171         if (CONTACTS_ERROR_NONE != ret) {
1172                 snprintf(query, sizeof(query),
1173                                 "SELECT contact_id "
1174                                 "FROM %s "
1175                                 "WHERE person_id = %d AND deleted = 0 "
1176                                 "ORDER BY contact_id",
1177                                 CTS_TABLE_CONTACTS, person_id);
1178                 ret = ctsvc_query_prepare(query, &stmt);
1179                 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1180
1181                 while (1 == ctsvc_stmt_step(stmt)) {
1182                         int contact_id = ctsvc_stmt_get_int(stmt, 0);
1183                         cts_stmt stmt_email;
1184
1185                         snprintf(query, sizeof(query),
1186                                         "SELECT id, is_default FROM %s "
1187                                         "WHERE contact_id = %d AND datatype = %d AND is_default = 1 AND is_my_profile = 0",
1188                                         CTS_TABLE_DATA, contact_id, CONTACTS_DATA_TYPE_EMAIL);
1189
1190                         ret = ctsvc_query_prepare(query, &stmt_email);
1191                         if (NULL == stmt_email) {
1192                                 /* LCOV_EXCL_START */
1193                                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
1194                                 ctsvc_stmt_finalize(stmt);
1195                                 return ret;
1196                                 /* LCOV_EXCL_STOP */
1197                         }
1198
1199                         if (1 == ctsvc_stmt_step(stmt_email)) {
1200                                 int default_email_id = ctsvc_stmt_get_int(stmt_email, 0);
1201                                 __ctsvc_put_person_default_data(person_id, default_email_id, CONTACTS_DATA_TYPE_EMAIL);
1202                                 ctsvc_stmt_finalize(stmt_email);
1203                                 break;
1204                         }
1205                         ctsvc_stmt_finalize(stmt_email);
1206                 }
1207                 ctsvc_stmt_finalize(stmt);
1208         } else {
1209                 contacts_record_destroy(record, true);
1210         }
1211
1212         ret = __ctsvc_get_person_value(CTSVC_GET_PERSON_DEFAULT_IMAGE_VALUE, person_id, &record);
1213         if (CONTACTS_ERROR_NONE != ret) {
1214                 snprintf(query, sizeof(query),
1215                                 "SELECT contact_id "
1216                                 "FROM %s "
1217                                 "WHERE person_id = %d AND deleted = 0 "
1218                                 "ORDER BY contact_id",
1219                                 CTS_TABLE_CONTACTS, person_id);
1220                 ret = ctsvc_query_prepare(query, &stmt);
1221                 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1222
1223                 while (1 == ctsvc_stmt_step(stmt)) {
1224                         int contact_id = ctsvc_stmt_get_int(stmt, 0);
1225                         cts_stmt stmt_image;
1226
1227                         snprintf(query, sizeof(query),
1228                                         "SELECT id, is_default FROM %s "
1229                                         "WHERE contact_id = %d AND datatype = %d AND is_default = 1 AND is_my_profile = 0",
1230                                         CTS_TABLE_DATA, contact_id, CONTACTS_DATA_TYPE_IMAGE);
1231
1232                         ret = ctsvc_query_prepare(query, &stmt_image);
1233                         if (NULL == stmt_image) {
1234                                 /* LCOV_EXCL_START */
1235                                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
1236                                 ctsvc_stmt_finalize(stmt);
1237                                 return ret;
1238                                 /* LCOV_EXCL_STOP */
1239                         }
1240
1241                         if (1 == ctsvc_stmt_step(stmt_image)) {
1242                                 int default_image_id = ctsvc_stmt_get_int(stmt_image, 0);
1243                                 __ctsvc_put_person_default_image(person_id, default_image_id);
1244                                 ctsvc_stmt_finalize(stmt_image);
1245                                 break;
1246                         }
1247                         ctsvc_stmt_finalize(stmt_image);
1248                 }
1249                 ctsvc_stmt_finalize(stmt);
1250         } else {
1251                 contacts_record_destroy(record, true);
1252         }
1253
1254         return CONTACTS_ERROR_NONE;
1255 }
1256
1257 int ctsvc_person_unlink_contact(int person_id, int contact_id, int *out_person_id)
1258 {
1259         int ret;
1260         int id;
1261         int link_count = 0;
1262         char query[CTS_SQL_MIN_LEN] = {0};
1263         contacts_record_h record = NULL;
1264         bool is_favorite = false;
1265         double priority = 0.0;
1266
1267         RETVM_IF(person_id <= 0 || contact_id <= 0, CONTACTS_ERROR_INVALID_PARAMETER,
1268                         "person_id(%d), person_id(%d)", person_id, person_id);
1269
1270         if (out_person_id)
1271                 *out_person_id = 0;
1272
1273         ret = ctsvc_begin_trans();
1274         RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
1275
1276         snprintf(query, sizeof(query),
1277                         "SELECT link_count FROM "CTS_TABLE_PERSONS" WHERE person_id=%d", person_id);
1278         ret = ctsvc_query_get_first_int_result(query, &link_count);
1279         if (CONTACTS_ERROR_NONE != ret) {
1280                 ctsvc_end_trans(false);
1281                 return ret;
1282         }
1283
1284         if (link_count == 1) {
1285                 /* LCOV_EXCL_START */
1286                 ERR("This person(%d) has one contact(%d)", person_id, contact_id);
1287                 ctsvc_end_trans(false);
1288                 return CONTACTS_ERROR_INVALID_PARAMETER;
1289                 /* LCOV_EXCL_STOP */
1290         }
1291
1292         ret = ctsvc_db_contact_get(contact_id, (contacts_record_h*)&record);
1293         if (CONTACTS_ERROR_NONE != ret) {
1294                 /* LCOV_EXCL_START */
1295                 ERR("ctsvc_db_contact_get() Fail(%d)", ret);
1296                 ctsvc_end_trans(false);
1297                 return ret;
1298                 /* LCOV_EXCL_STOP */
1299         }
1300
1301         /* create new person */
1302         id = ctsvc_db_insert_person(record);
1303         if (id < CONTACTS_ERROR_NONE) {
1304                 /* LCOV_EXCL_START */
1305                 ERR("ctsvc_db_insert_person() Fail(%d)", id);
1306                 ctsvc_end_trans(false);
1307                 contacts_record_destroy(record, true);
1308                 return id;
1309                 /* LCOV_EXCL_STOP */
1310         }
1311
1312         /* insert statistic info for new person */
1313         snprintf(query, sizeof(query),
1314                         "INSERT INTO %s (person_id, usage_type, times_used) "
1315                         "SELECT %d, usage_type, times_used FROM %s WHERE person_id = %d",
1316                         CTS_TABLE_CONTACT_STAT, id, CTS_TABLE_CONTACT_STAT, person_id);
1317         ret = ctsvc_query_exec(query);
1318         if (CONTACTS_ERROR_NONE != ret) {
1319                 /* LCOV_EXCL_START */
1320                 ERR("ctsvc_query_exec() Fail(%d)", ret);
1321                 ctsvc_end_trans(false);
1322                 contacts_record_destroy(record, true);
1323                 return ret;
1324                 /* LCOV_EXCL_STOP */
1325         }
1326
1327         is_favorite = __ctsvc_get_person_favorite_info(person_id, &priority);
1328
1329         /* update person_id of unlinked contact */
1330         snprintf(query, sizeof(query),
1331                         "UPDATE %s SET person_id = %d WHERE contact_id = %d",
1332                         CTS_TABLE_CONTACTS, id, contact_id);
1333         ret = ctsvc_query_exec(query);
1334         if (CONTACTS_ERROR_NONE != ret) {
1335                 /* LCOV_EXCL_START */
1336                 ERR("ctsvc_query_exec() Fail(%d)", ret);
1337                 ctsvc_end_trans(false);
1338                 contacts_record_destroy(record, true);
1339                 return ret;
1340                 /* LCOV_EXCL_STOP */
1341         }
1342
1343         /* update bsae person info */
1344         ret = ctsvc_person_aggregate(person_id);
1345         if (CONTACTS_ERROR_NONE != ret) {
1346                 /* LCOV_EXCL_START */
1347                 ERR("ctsvc_person_aggregate(%d) Fail(%d)", person_id, ret);
1348                 ctsvc_end_trans(false);
1349                 contacts_record_destroy(record, true);
1350                 return ret;
1351                 /* LCOV_EXCL_STOP */
1352         }
1353
1354         if (is_favorite && ((ctsvc_contact_s*)record)->is_favorite) {
1355                 snprintf(query, sizeof(query),
1356                                 "INSERT OR REPLACE INTO "CTS_TABLE_FAVORITES" values(%d, %f)", id, priority);
1357                 ret = ctsvc_query_exec(query);
1358                 if (CONTACTS_ERROR_NONE != ret) {
1359                         /* LCOV_EXCL_START */
1360                         ERR("ctsvc_query_exec() Fail(%d)", ret);
1361                         ctsvc_end_trans(false);
1362                         contacts_record_destroy(record, true);
1363                         return ret;
1364                         /* LCOV_EXCL_STOP */
1365                 }
1366         }
1367         contacts_record_destroy(record, true);
1368
1369         __ctsvc_update_primary_default_data(person_id);
1370
1371 #ifdef ENABLE_LOG_FEATURE
1372         /* update phonelog */
1373         ctsvc_db_phone_log_update_person_id(NULL, person_id, id, false, NULL);
1374 #endif /* ENABLE_LOG_FEATURE */
1375
1376         if (out_person_id)
1377                 *out_person_id = id;
1378         ctsvc_set_person_noti();
1379         ret = ctsvc_end_trans(true);
1380         if (ret < CONTACTS_ERROR_NONE) {
1381                 /* LCOV_EXCL_START */
1382                 ERR("ctsvc_end_trans() Fail(%d)", ret);
1383                 return ret;
1384                 /* LCOV_EXCL_STOP */
1385         } else {
1386                 return CONTACTS_ERROR_NONE;
1387         }
1388 }
1389
1390 int ctsvc_person_do_garbage_collection(void)
1391 {
1392         int ret;
1393         cts_stmt stmt = NULL;
1394         char query[CTS_SQL_MIN_LEN] = {0};
1395
1396         snprintf(query, sizeof(query), "SELECT person_id FROM "CTS_TABLE_PERSONS" WHERE dirty=1");
1397
1398         ret = ctsvc_query_prepare(query, &stmt);
1399         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1400
1401         while (1 /*CTS_TRUE*/ == ctsvc_stmt_step(stmt)) {
1402                 int person_id;
1403                 person_id = ctsvc_stmt_get_int(stmt, 0);
1404                 ctsvc_person_aggregate(person_id);
1405 #ifdef ENABLE_LOG_FEATURE
1406                 /* update phonelog */
1407                 ctsvc_db_phone_log_update_person_id(NULL, person_id, -1, false, NULL);
1408 #endif /* ENABLE_LOG_FEATURE */
1409         }
1410         ctsvc_stmt_finalize(stmt);
1411
1412         return CONTACTS_ERROR_NONE;
1413 }
1414
1415 int ctsvc_person_reset_usage(int person_id, contacts_usage_type_e type)
1416 {
1417         int ret ;
1418         char query[CTS_SQL_MAX_LEN] = {0};
1419
1420         RETVM_IF(person_id <= 0, CONTACTS_ERROR_INVALID_PARAMETER, "contact_id should be greater than 0");
1421
1422         snprintf(query, sizeof(query),
1423                         "UPDATE %s SET times_used = 0 WHERE person_id = %d AND usage_type = %d",
1424                         CTS_TABLE_CONTACT_STAT, person_id, type);
1425
1426         ret = ctsvc_begin_trans();
1427         RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
1428
1429         ret = ctsvc_query_exec(query);
1430         if (CONTACTS_ERROR_NONE != ret) {
1431                 /* LCOV_EXCL_START */
1432                 ERR("ctsvc_query_exec() Fail(%d)", ret);
1433                 ctsvc_end_trans(false);
1434                 return ret;
1435                 /* LCOV_EXCL_STOP */
1436         }
1437
1438         ret = ctsvc_end_trans(true);
1439         if (ret < CONTACTS_ERROR_NONE) {
1440                 /* LCOV_EXCL_START */
1441                 ERR("ctsvc_end_trans() Fail(%d)", ret);
1442                 return ret;
1443                 /* LCOV_EXCL_STOP */
1444         } else {
1445                 return CONTACTS_ERROR_NONE;
1446         }
1447 }
1448
1449 int ctsvc_person_set_favorite_order(int person_id, int front_person_id, int back_person_id)
1450 {
1451         int ret;
1452         double front_prio = 0.0;
1453         double back_prio = 0.0;
1454         double prio;
1455         cts_stmt stmt;
1456         char query[CTS_SQL_MAX_LEN] = {0};
1457
1458         snprintf(query, sizeof(query), "SELECT favorite_prio FROM "CTS_TABLE_FAVORITES" WHERE person_id = ?");
1459
1460         ret = ctsvc_query_prepare(query, &stmt);
1461         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1462
1463         ctsvc_stmt_bind_int(stmt, 1, front_person_id);
1464         ret = ctsvc_stmt_step(stmt);
1465         if (1 /*CTS_TRUE*/  == ret)
1466                 front_prio = ctsvc_stmt_get_dbl(stmt, 0);
1467         ctsvc_stmt_reset(stmt);
1468         ctsvc_stmt_bind_int(stmt, 1, back_person_id);
1469         ret = ctsvc_stmt_step(stmt);
1470         if (1 /*CTS_TRUE*/ == ret)
1471                 back_prio = ctsvc_stmt_get_dbl(stmt, 0);
1472         ctsvc_stmt_finalize(stmt);
1473
1474         RETVM_IF(0.0 == front_prio && 0.0 == back_prio, CONTACTS_ERROR_INVALID_PARAMETER,
1475                         "The indexes for front and back are invalid.");
1476
1477         if (0.0 == back_prio)
1478                 prio = front_prio + 1;
1479         else
1480                 prio = (front_prio + back_prio) / 2;
1481
1482         ret = ctsvc_begin_trans();
1483         RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
1484
1485         snprintf(query, sizeof(query),
1486                         "UPDATE %s SET favorite_prio = %f WHERE person_id = %d",
1487                         CTS_TABLE_FAVORITES, prio, person_id);
1488
1489         ret = ctsvc_query_exec(query);
1490         if (CONTACTS_ERROR_NONE != ret) {
1491                 /* LCOV_EXCL_START */
1492                 ERR("ctsvc_query_exec() Fail(%d)", ret);
1493                 ctsvc_end_trans(false);
1494                 return ret;
1495                 /* LCOV_EXCL_STOP */
1496         }
1497
1498         ctsvc_set_person_noti();
1499
1500         ret = ctsvc_end_trans(true);
1501         if (ret < CONTACTS_ERROR_NONE) {
1502                 /* LCOV_EXCL_START */
1503                 ERR("ctsvc_end_trans() Fail(%d)", ret);
1504                 return ret;
1505                 /* LCOV_EXCL_STOP */
1506         } else {
1507                 return CONTACTS_ERROR_NONE;
1508         }
1509 }
1510
1511 int ctsvc_person_set_default_property(contacts_person_property_e property, int person_id,
1512                 int id)
1513 {
1514         int ret;
1515
1516         ret = ctsvc_begin_trans();
1517         RETVM_IF(ret < CONTACTS_ERROR_NONE, CONTACTS_ERROR_DB, "ctsvc_begin_trans() Fail(%d)", ret);
1518
1519         switch (property) {
1520         case CONTACTS_PERSON_PROPERTY_NAME_CONTACT:
1521                 ret = __ctsvc_put_person_default_name(person_id, id);           /* contact id */
1522                 break;
1523         case CONTACTS_PERSON_PROPERTY_NUMBER:
1524                 ret = __ctsvc_put_person_default_data(person_id, id, CONTACTS_DATA_TYPE_NUMBER);        /* number id */
1525                 break;
1526         case CONTACTS_PERSON_PROPERTY_EMAIL:
1527                 ret = __ctsvc_put_person_default_data(person_id, id, CONTACTS_DATA_TYPE_EMAIL);         /* email id */
1528                 break;
1529         case CONTACTS_PERSON_PROPERTY_IMAGE:
1530                 ret = __ctsvc_put_person_default_image(person_id, id);          /* image id */
1531                 break;
1532         default:
1533                 ret = CONTACTS_ERROR_INVALID_PARAMETER;
1534                 break;
1535         }
1536         if (ret < CONTACTS_ERROR_NONE) {
1537                 /* LCOV_EXCL_START */
1538                 ERR("contacts_person_set_default_property() Fail(%d) : person property (%d)", ret, property);
1539                 ctsvc_end_trans(false);
1540                 return ret;
1541                 /* LCOV_EXCL_STOP */
1542         }
1543
1544 #ifdef _CONTACTS_IPC_SERVER
1545         ctsvc_change_subject_add_changed_person_id(CONTACTS_CHANGE_UPDATED, person_id);
1546 #endif
1547         ctsvc_set_person_noti();
1548         ret = ctsvc_end_trans(true);
1549
1550         return ret;
1551 }
1552
1553 int ctsvc_person_get_default_property(contacts_person_property_e property, int person_id,
1554                 int *id)
1555 {
1556         int ret = CONTACTS_ERROR_NONE;
1557         char query[CTS_SQL_MAX_LEN] = {0};
1558
1559         RETVM_IF(person_id <= 0 || id == NULL, CONTACTS_ERROR_INVALID_PARAMETER, "id should be greater than 0");
1560         *id = 0;
1561
1562         switch (property) {
1563         case CONTACTS_PERSON_PROPERTY_NAME_CONTACT:
1564                 snprintf(query, sizeof(query),
1565                                 "SELECT name_contact_id FROM "CTS_TABLE_PERSONS" WHERE person_id = %d",
1566                                 person_id);
1567                 break;
1568         case CONTACTS_PERSON_PROPERTY_NUMBER:
1569                 snprintf(query, sizeof(query),
1570                                 "SELECT id FROM "CTS_TABLE_DATA" WHERE is_primary_default = 1 AND datatype = %d AND is_my_profile = 0 AND "
1571                                 "contact_id in (SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
1572                                 "WHERE person_id = %d AND deleted = 0)",
1573                                 CONTACTS_DATA_TYPE_NUMBER, person_id);
1574                 break;
1575         case CONTACTS_PERSON_PROPERTY_EMAIL:
1576                 snprintf(query, sizeof(query),
1577                                 "SELECT id FROM "CTS_TABLE_DATA" WHERE is_primary_default = 1 AND datatype = %d AND is_my_profile = 0 AND "
1578                                 "contact_id in (SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
1579                                 "WHERE person_id = %d AND deleted = 0)",
1580                                 CONTACTS_DATA_TYPE_EMAIL, person_id);
1581                 break;
1582         case CONTACTS_PERSON_PROPERTY_IMAGE:
1583                 snprintf(query, sizeof(query),
1584                                 "SELECT id FROM "CTS_TABLE_DATA" WHERE is_primary_default = 1 AND datatype = %d AND is_my_profile = 0 AND "
1585                                 "contact_id in (SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
1586                                 "WHERE person_id = %d AND deleted = 0)",
1587                                 CONTACTS_DATA_TYPE_IMAGE, person_id);
1588                 break;
1589         default:
1590                 ret = CONTACTS_ERROR_INVALID_PARAMETER;
1591                 break;
1592         }
1593
1594         if (*query) {
1595                 int result = 0;
1596                 ret = ctsvc_query_get_first_int_result(query, &result);
1597                 RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "ctsvc_query_get_first_int_result() Fail(%d)", ret);
1598                 *id = result;
1599         }
1600
1601         return ret;
1602 }
1603
1604 static void __ctsvc_collate_numbers(contacts_record_h record, GSList **nums)
1605 {
1606         int ret = CONTACTS_ERROR_NONE;
1607         GList *cursor = NULL;
1608         ctsvc_contact_s *contact = (ctsvc_contact_s*)record;
1609         ctsvc_number_s *number_data;
1610
1611         if (NULL == contact->numbers) {
1612                 DBG("NULL == contact->numbers");
1613                 return;
1614         }
1615
1616         for (cursor = contact->numbers->records; cursor; cursor = cursor->next) {
1617                 number_data = cursor->data;
1618                 if (number_data && number_data->normalized && number_data->normalized[0]) {
1619                         char minmatch[strlen(number_data->normalized) + 1];
1620                         ret = ctsvc_get_minmatch_number(number_data->normalized, minmatch, sizeof(minmatch),
1621                                         ctsvc_get_phonenumber_min_match_digit());
1622
1623                         if (CONTACTS_ERROR_NONE != ret)
1624                                 continue;
1625
1626                         if (NULL == *nums || NULL == g_slist_find(*nums, minmatch))
1627                                 *nums = g_slist_append(*nums, strdup(minmatch));
1628                 }
1629         }
1630
1631 }
1632
1633 static void __ctsvc_collate_emails(contacts_record_h record, GSList **emails)
1634 {
1635         GList *cursor = NULL;
1636         ctsvc_contact_s *contact = (ctsvc_contact_s*)record;
1637         ctsvc_email_s *email_data;
1638         int local_part_len = 0;
1639         char local_part[256] = {0};
1640
1641         if (NULL == contact->emails) {
1642                 DBG("NULL == contact->emails");
1643                 return;
1644         }
1645
1646         for (cursor = contact->emails->records; cursor; cursor = cursor->next) {
1647                 email_data = cursor->data;
1648                 if (email_data && email_data->email_addr && email_data->email_addr[0]) {
1649                         local_part_len = strcspn(email_data->email_addr, "@");
1650                         if (local_part_len <= 0 || strlen(email_data->email_addr) <= local_part_len)
1651                                 continue;
1652
1653                         strncpy(local_part, email_data->email_addr, local_part_len + 1);
1654
1655                         if (NULL == *emails || NULL == g_slist_find(*emails, local_part))
1656                                 *emails = g_slist_append(*emails, strdup(local_part));
1657                 }
1658         }
1659 }
1660
1661 static void __ctsvc_collate_names(contacts_record_h record, GSList **names)
1662 {
1663         ctsvc_contact_s *contact = (ctsvc_contact_s*)record;
1664         int comp_name_len = CTSVC_COMP_NAME_LEN;
1665         char comp_name[256] = {0};
1666         char *name = NULL;
1667
1668         if (CONTACTS_DISPLAY_NAME_SOURCE_TYPE_NAME == contact->display_source_type)
1669                 name = contact->reverse_sort_name;
1670
1671         if (name && comp_name_len <= strlen(name)) {
1672                 if (CTSVC_SORT_KOREAN == contact->display_name_language) { /*compare first name*/
1673                         strncpy(comp_name, name + (strlen(name) -comp_name_len),
1674                                         comp_name_len);
1675                 } else {  /*compare last name*/
1676                         comp_name_len = strcspn(name, ", ");
1677                         strncpy(comp_name, name, comp_name_len);
1678                 }
1679
1680                 if (NULL == *names || NULL == g_slist_find(*names, comp_name))
1681                         *names = g_slist_append(*names, strdup(comp_name));
1682         }
1683 }
1684
1685
1686 static int __ctsvc_get_person_info_by_person_id(int person_id, GSList **nums, GSList **emails, GSList **names)
1687 {
1688         int ret = CONTACTS_ERROR_NONE;
1689         GSList *contact_ids = NULL;
1690         GSList *cursor = NULL;
1691
1692         char query[CTS_SQL_MIN_LEN] = {0};
1693         cts_stmt stmt;
1694
1695         snprintf(query, sizeof(query),
1696                         "SELECT contact_id FROM "CTS_TABLE_CONTACTS" "
1697                         "WHERE deleted = 0 AND person_id = %d", person_id);
1698
1699         ret = ctsvc_query_prepare(query, &stmt);
1700         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1701
1702         while ((ret = ctsvc_stmt_step(stmt))) {
1703                 int contact_id = 0;
1704
1705                 if (1 != ret) {
1706                         /* LCOV_EXCL_START */
1707                         ERR("ctsvc_stmt_step() Fail(%d)", ret);
1708                         ctsvc_stmt_finalize(stmt);
1709                         return ret;
1710                         /* LCOV_EXCL_STOP */
1711                 }
1712                 contact_id = ctsvc_stmt_get_int(stmt, 0);
1713
1714                 contact_ids = g_slist_append(contact_ids, GINT_TO_POINTER(contact_id));
1715         }
1716         ctsvc_stmt_finalize(stmt);
1717
1718         if (NULL == contact_ids) {
1719                 /* LCOV_EXCL_START */
1720                 ERR("Fail to get contacts by person_id");
1721                 return CONTACTS_ERROR_DB;
1722                 /* LCOV_EXCL_STOP */
1723         }
1724
1725         for (cursor = contact_ids; cursor; cursor = cursor->next) {
1726                 contacts_record_h record = NULL;
1727
1728                 int contact_id = GPOINTER_TO_INT(cursor->data);
1729                 ret = ctsvc_db_contact_get(contact_id, &record);
1730                 if (CONTACTS_ERROR_NONE != ret) {
1731                         WARN("ctsvc_db_contact_get() Fail(%d), contact_id = %d", ret, contact_id);
1732                         continue;
1733                 }
1734
1735                 __ctsvc_collate_numbers(record, nums);
1736                 __ctsvc_collate_emails(record, emails);
1737                 __ctsvc_collate_names(record, names);
1738
1739                 contacts_record_destroy(record, true);
1740         }
1741
1742         g_slist_free(contact_ids);
1743
1744         return ret;
1745 }
1746
1747 static void __ctsvc_make_sub_query_by_num(GSList *nums, int person_id,
1748                 char **sub_query, int *sub_size, int *sub_len)
1749 {
1750         GSList *cursor = NULL;
1751         char temp_query[CTS_SQL_MIN_LEN] = {0};
1752
1753         /* Add 2 points whenever a number is matched */
1754         snprintf(temp_query, CTS_SQL_MIN_LEN,
1755                         "SELECT C.person_id, 2 score FROM "CTS_TABLE_CONTACTS" C, "CTS_TABLE_DATA" D "
1756                         "ON C.contact_id=D.contact_id AND D.datatype=%d AND C.deleted = 0 "
1757                         "AND C.person_id <> %d AND D.is_my_profile = 0 "
1758                         "WHERE D.data4 = '",
1759                         CONTACTS_DATA_TYPE_NUMBER, person_id);
1760
1761         for (cursor = nums; cursor; cursor = cursor->next) {
1762                 char *minmatch = cursor->data;
1763                 if (NULL == minmatch)
1764                         continue;
1765
1766                 if (*sub_len)
1767                         *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, " UNION ALL ");
1768
1769                 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, temp_query);
1770                 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, minmatch);
1771                 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, "'");
1772         }
1773 }
1774
1775 static void __ctsvc_make_sub_query_by_email(GSList *emails, int person_id,
1776                 char **sub_query, int *sub_size, int *sub_len)
1777 {
1778         GSList *cursor = NULL;
1779         char temp_query[CTS_SQL_MIN_LEN] = {0};
1780
1781         /* Add 2 points whenever a email id is matched */
1782         snprintf(temp_query, CTS_SQL_MIN_LEN,
1783                         "SELECT C.person_id, 2 score FROM "CTS_TABLE_CONTACTS" C, "CTS_TABLE_DATA" D "
1784                         "ON C.contact_id=D.contact_id AND D.datatype=%d AND C.deleted = 0 "
1785                         "AND C.person_id <> %d AND D.is_my_profile = 0 "
1786                         "WHERE D.data3 LIKE '",
1787                         CONTACTS_DATA_TYPE_EMAIL, person_id);
1788
1789         for (cursor = emails; cursor; cursor = cursor->next) {
1790                 char *local_part = cursor->data;
1791                 if (NULL == local_part)
1792                         continue;
1793
1794                 if (*sub_len)
1795                         *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, " UNION ALL ");
1796
1797                 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, temp_query);
1798                 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, local_part);
1799                 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, "%'");
1800         }
1801 }
1802
1803 static void __ctsvc_make_sub_query_by_name(GSList *names, int person_id,
1804                 char **sub_query, int *sub_size, int *sub_len)
1805 {
1806         GSList *cursor = NULL;
1807         char temp_query[CTS_SQL_MIN_LEN] = {0};
1808
1809         /* Add 1 point whenever last name is matched (first name in case of Korean) */
1810         snprintf(temp_query, CTS_SQL_MIN_LEN,
1811                         "SELECT person_id, 1 score FROM "CTS_TABLE_CONTACTS" "
1812                         "WHERE person_id <> %d AND display_name_source=%d "
1813                         "AND reverse_sort_name LIKE '",
1814                         person_id, CONTACTS_DISPLAY_NAME_SOURCE_TYPE_NAME);
1815
1816         for (cursor = names; cursor; cursor = cursor->next) {
1817                 char *name = cursor->data;
1818                 if (NULL == name)
1819                         continue;
1820
1821                 int sort_type = ctsvc_get_name_sort_type(name);
1822
1823                 if (*sub_len)
1824                         *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, " UNION ALL ");
1825
1826                 *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, temp_query);
1827                 if (CTSVC_SORT_KOREAN == sort_type) {  /*compare first name*/
1828                         *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, "%");
1829                         *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, name);
1830                         *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, "'");
1831                 } else {  /*compare last name*/
1832                         *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, name);
1833                         *sub_len += SAFE_SNPRINTF(sub_query, sub_size, *sub_len, "%'");
1834                 }
1835         }
1836 }
1837
1838 int ctsvc_person_get_aggregation_suggestions(int person_id, int limit, contacts_list_h *out_list)
1839 {
1840         int ret = CONTACTS_ERROR_NONE;
1841         int id = 0;
1842         int cnt = 0;
1843         int score = 0;
1844         GSList *nums = NULL;
1845         GSList *emails = NULL;
1846         GSList *names = NULL;
1847         char *query = NULL;
1848         char *sub_query = NULL;
1849         int query_size = 0;
1850         int sub_len = 0;
1851         int sub_size = CTS_SQL_MAX_LEN;
1852         contacts_list_h list = NULL;
1853         cts_stmt stmt = NULL;
1854
1855         RETV_IF(person_id <= 0, CONTACTS_ERROR_INVALID_PARAMETER);
1856         RETV_IF(NULL == out_list, CONTACTS_ERROR_INVALID_PARAMETER);
1857
1858         CTS_FN_CALL;
1859
1860         ret = __ctsvc_get_person_info_by_person_id(person_id, &nums, &emails, &names);
1861         if (CONTACTS_ERROR_NONE != ret) {
1862                 /* LCOV_EXCL_START */
1863                 ERR("__ctsvc_get_person_info_by_person_id() Fail(%d)", ret);
1864                 return ret;
1865                 /* LCOV_EXCL_STOP */
1866         }
1867
1868         sub_query = calloc(1, sub_size);
1869         if (NULL == sub_query) {
1870                 /* LCOV_EXCL_START */
1871                 ERR("calloc() Fail");
1872                 g_slist_free_full(nums, free);
1873                 g_slist_free_full(emails, free);
1874                 g_slist_free_full(names, free);
1875                 return CONTACTS_ERROR_OUT_OF_MEMORY;
1876                 /* LCOV_EXCL_STOP */
1877         }
1878
1879         if (nums) {
1880                 __ctsvc_make_sub_query_by_num(nums, person_id, &sub_query, &sub_size, &sub_len);
1881                 g_slist_free_full(nums, free);
1882         }
1883
1884         if (emails) {
1885                 __ctsvc_make_sub_query_by_email(emails, person_id, &sub_query, &sub_size, &sub_len);
1886                 g_slist_free_full(emails, free);
1887         }
1888
1889         if (names) {
1890                 __ctsvc_make_sub_query_by_name(names, person_id, &sub_query, &sub_size, &sub_len);
1891                 g_slist_free_full(names, free);
1892         }
1893
1894         if (0 == sub_len) {
1895                 *out_list = NULL;
1896                 free(sub_query);
1897                 DBG("no numbers, emails, names for query");
1898                 return CONTACTS_ERROR_NO_DATA;
1899         }
1900
1901         query_size = CTS_SQL_MIN_LEN + sub_len;
1902         query = calloc(1, query_size);
1903         if (NULL == query) {
1904                 /* LCOV_EXCL_START */
1905                 ERR("calloc() Fail");
1906                 free(sub_query);
1907                 return CONTACTS_ERROR_OUT_OF_MEMORY;
1908                 /* LCOV_EXCL_STOP */
1909         }
1910
1911         snprintf(query, query_size,
1912                         "SELECT person_id, sum(score) FROM (%s) "
1913                         "GROUP BY person_id ORDER BY score DESC",
1914                         sub_query);
1915         ret = ctsvc_query_prepare(query, &stmt);
1916         if (NULL == stmt) {
1917                 /* LCOV_EXCL_START */
1918                 ERR("ctsvc_query_prepare fail(%d)", ret);
1919                 free(sub_query);
1920                 free(query);
1921                 return ret;
1922                 /* LCOV_EXCL_STOP */
1923         }
1924
1925         sub_len = 0;
1926         while ((ret = ctsvc_stmt_step(stmt))) {
1927                 if (1 != ret) {
1928                         /* LCOV_EXCL_START */
1929                         ERR("ctsvc_stmt_step() Fail(%d)", ret);
1930                         ctsvc_stmt_finalize(stmt);
1931                         free(sub_query);
1932                         free(query);
1933                         return ret;
1934                         /* LCOV_EXCL_STOP */
1935                 }
1936                 id = ctsvc_stmt_get_int(stmt, 0);
1937                 score = ctsvc_stmt_get_int(stmt, 1);
1938                 DBG("person_id : %d, score : %d", id, score);
1939
1940                 /* Add 2 points whenever a email id or a number is matched */
1941                 /* and 1 point whenever some part of name is matched */
1942                 /* Aggregation suggestions: the persons who get more than 2 points */
1943                 if (CTSVC_AGGREGATION_SUGGESTION_SCORE <= score && (0 == limit || cnt < limit)) {
1944                         cnt++;
1945                         if (sub_len)
1946                                 sub_len += snprintf(sub_query + sub_len, sub_size -sub_len, ", %d", id);
1947                         else
1948                                 sub_len += snprintf(sub_query + sub_len, sub_size -sub_len, "%d", id);
1949                 }
1950         }
1951         ctsvc_stmt_finalize(stmt);
1952
1953         if (0 == sub_len) {
1954                 *out_list = NULL;
1955                 free(sub_query);
1956                 DBG("no person_id for aggregation suggestions");
1957                 return CONTACTS_ERROR_NO_DATA;
1958         }
1959
1960         snprintf(query, query_size,
1961                         "SELECT DISTINCT persons.person_id, "
1962                         "%s, "
1963                         "_NORMALIZE_INDEX_(%s), "
1964                         "name_contact_id, "
1965                         "persons.image_thumbnail_path, "
1966                         "persons.ringtone_path, "
1967                         "persons.vibration, "
1968                         "persons.message_alert, "
1969                         "status, "
1970                         "link_count, "
1971                         "addressbook_ids, "
1972                         "persons.has_phonenumber, "
1973                         "persons.has_email, "
1974                         "EXISTS(SELECT person_id FROM "CTS_TABLE_FAVORITES" WHERE person_id=persons.person_id) is_favorite "
1975                         "FROM "CTS_TABLE_PERSONS" "
1976                         "LEFT JOIN "CTS_TABLE_CONTACTS" "
1977                         "ON (name_contact_id = contacts.contact_id AND contacts.deleted = 0) "
1978                         "WHERE persons.person_id IN (%s)",
1979                         ctsvc_get_display_column(), ctsvc_get_sort_name_column(), sub_query);
1980
1981         free(sub_query);
1982
1983         ret = ctsvc_query_prepare(query, &stmt);
1984         free(query);
1985         if (NULL == stmt) {
1986                 /* LCOV_EXCL_START */
1987                 ERR("ctsvc_query_prepare fail(%d)", ret);
1988                 return ret;
1989                 /* LCOV_EXCL_STOP */
1990         }
1991
1992         contacts_list_create(&list);
1993         while ((ret = ctsvc_stmt_step(stmt))) {
1994                 contacts_record_h record;
1995                 if (1 != ret) {
1996                         /* LCOV_EXCL_START */
1997                         ERR("ctsvc_stmt_step() Fail(%d)", ret);
1998                         ctsvc_stmt_finalize(stmt);
1999                         contacts_list_destroy(list, true);
2000                         return ret;
2001                         /* LCOV_EXCL_STOP */
2002                 }
2003                 ret = ctsvc_db_person_create_record_from_stmt(stmt, &record);
2004                 if (CONTACTS_ERROR_NONE != ret) {
2005                         /* LCOV_EXCL_START */
2006                         ERR("ctsvc_db_person_create_record_from_stmt() Fail(%d)", ret);
2007                         ctsvc_stmt_finalize(stmt);
2008                         contacts_list_destroy(list, true);
2009                         return ret;
2010                         /* LCOV_EXCL_STOP */
2011                 }
2012
2013                 ctsvc_list_prepend(list, record);
2014         }
2015         ctsvc_stmt_finalize(stmt);
2016         ctsvc_list_reverse(list);
2017
2018         *out_list = list;
2019
2020         return ret;
2021 }
2022