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