538f2fdee7ff4b78f413eebc13bd5d66fa154238
[platform/core/pim/contacts-service.git] / server / db / ctsvc_db_plugin_contact.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 #include <fcntl.h>
20 #include <unistd.h>
21
22 #include "contacts.h"
23 #include "ctsvc_internal.h"
24 #include "ctsvc_db_sqlite.h"
25 #include "ctsvc_db_schema.h"
26 #include "ctsvc_db_init.h"
27 #include "ctsvc_db_query.h"
28 #include "ctsvc_db_utils.h"
29 #include "ctsvc_record.h"
30 #include "ctsvc_normalize.h"
31 #include "ctsvc_number_utils.h"
32 #include "ctsvc_list.h"
33 #include "ctsvc_server_setting.h"
34 #include "ctsvc_localize_ch.h"
35 #include "ctsvc_server_group.h"
36 #include "ctsvc_notification.h"
37 #include "ctsvc_localize.h"
38 #include "ctsvc_localize_utils.h"
39 #include "ctsvc_server_person.h"
40 #include "ctsvc_notify.h"
41
42 #ifdef ENABLE_LOG_FEATURE
43 #include "ctsvc_server_phonelog.h"
44 #endif /* ENABLE_LOG_FEATURE */
45 #include "ctsvc_db_access_control.h"
46
47 #include "ctsvc_db_plugin_contact_helper.h"
48 #include "ctsvc_db_plugin_person_helper.h"
49
50
51 static int __ctsvc_db_get_contact_base_info(int id, ctsvc_contact_s *contact)
52 {
53         int ret;
54         int i;
55         cts_stmt stmt = NULL;
56         char query[CTS_SQL_MAX_LEN] = {0};
57         char *temp;
58         char full_path[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
59
60         snprintf(query, sizeof(query),
61                         "SELECT contact_id, addressbook_id, person_id, changed_time, changed_ver, link_mode, %s, "
62                         "display_name_source, image_thumbnail_path, "
63                         "ringtone_path, vibration, message_alert, "
64                         "uid, is_favorite, has_phonenumber, has_email, "
65                         "sort_name, reverse_sort_name "
66                         "FROM "CTS_TABLE_CONTACTS" WHERE contact_id = %d AND deleted = 0",
67                         ctsvc_get_display_column(), id);
68
69         ret = ctsvc_query_prepare(query, &stmt);
70         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
71
72         ret = ctsvc_stmt_step(stmt);
73         if (1 /*CTS_TRUE*/ != ret) {
74                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
75                 ctsvc_stmt_finalize(stmt);
76                 if (CONTACTS_ERROR_NONE == ret)
77                         return CONTACTS_ERROR_NO_DATA;
78                 else
79                         return ret;
80         }
81
82         i = 0;
83         contact->id = ctsvc_stmt_get_int(stmt, i++);
84         contact->addressbook_id = ctsvc_stmt_get_int(stmt, i++);
85         contact->person_id = ctsvc_stmt_get_int(stmt, i++);
86         contact->changed_time = ctsvc_stmt_get_int(stmt, i++);
87         contact->changed_ver = ctsvc_stmt_get_int(stmt, i++);
88         contact->link_mode = ctsvc_stmt_get_int(stmt, i++);
89         temp = ctsvc_stmt_get_text(stmt, i++);
90         contact->display_name = SAFE_STRDUP(temp);
91         contact->display_source_type = ctsvc_stmt_get_int(stmt, i++);
92
93         temp = ctsvc_stmt_get_text(stmt, i++);
94         if (temp) {
95                 snprintf(full_path, sizeof(full_path), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, temp);
96                 contact->image_thumbnail_path = strdup(full_path);
97         }
98
99         temp = ctsvc_stmt_get_text(stmt, i++);
100         contact->ringtone_path = SAFE_STRDUP(temp);
101         temp = ctsvc_stmt_get_text(stmt, i++);
102         contact->vibration = SAFE_STRDUP(temp);
103         temp = ctsvc_stmt_get_text(stmt, i++);
104         contact->message_alert = SAFE_STRDUP(temp);
105         temp = ctsvc_stmt_get_text(stmt, i++);
106         contact->uid = SAFE_STRDUP(temp);
107         contact->is_favorite = ctsvc_stmt_get_int(stmt, i++);
108         contact->has_phonenumber = ctsvc_stmt_get_int(stmt, i++);
109         contact->has_email = ctsvc_stmt_get_int(stmt, i++);
110         temp = ctsvc_stmt_get_text(stmt, i++);
111         contact->sort_name = SAFE_STRDUP(temp);
112         temp = ctsvc_stmt_get_text(stmt, i++);
113         contact->reverse_sort_name = SAFE_STRDUP(temp);
114         ctsvc_stmt_finalize(stmt);
115
116         return CONTACTS_ERROR_NONE;
117 }
118
119 static int __ctsvc_db_get_data(int id, ctsvc_contact_s *contact)
120 {
121         int ret;
122         int datatype;
123         cts_stmt stmt = NULL;
124         char query[CTS_SQL_MAX_LEN] = {0};
125
126         snprintf(query, sizeof(query),
127                         "SELECT datatype, id, data.contact_id, is_default, data1, data2, "
128                         "data3, data4, data5, data6, data7, data8, data9, data10, data11, data12 "
129                         "FROM "CTS_TABLE_DATA", "CTSVC_DB_VIEW_CONTACT" "
130                         "ON "CTS_TABLE_DATA".contact_id = "CTSVC_DB_VIEW_CONTACT".contact_id "
131                         "WHERE data.contact_id = %d  AND is_my_profile = 0 "
132                         "ORDER BY is_default DESC", id);
133
134         ret = ctsvc_query_prepare(query, &stmt);
135         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
136
137         ret = ctsvc_stmt_step(stmt);
138         if (1 /*CTS_TRUE */!= ret) {
139                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
140                 ctsvc_stmt_finalize(stmt);
141                 return ret;
142         }
143
144         do {
145                 datatype = ctsvc_stmt_get_int(stmt, 0);
146                 switch (datatype) {
147                 case CTSVC_DATA_NAME:
148                         ctsvc_get_data_info_name(stmt, (contacts_list_h)contact->name);
149                         break;
150                 case CTSVC_DATA_EVENT:
151                         ctsvc_get_data_info_event(stmt, (contacts_list_h)contact->events);
152                         break;
153                 case CTSVC_DATA_MESSENGER:
154                         ctsvc_get_data_info_messenger(stmt, (contacts_list_h)contact->messengers);
155                         break;
156                 case CTSVC_DATA_POSTAL:
157                         ctsvc_get_data_info_address(stmt, (contacts_list_h)contact->postal_addrs);
158                         break;
159                 case CTSVC_DATA_URL:
160                         ctsvc_get_data_info_url(stmt, (contacts_list_h)contact->urls);
161                         break;
162                 case CTSVC_DATA_NICKNAME:
163                         ctsvc_get_data_info_nickname(stmt, (contacts_list_h)contact->nicknames);
164                         break;
165                 case CTSVC_DATA_NUMBER:
166                         ctsvc_get_data_info_number(stmt, (contacts_list_h)contact->numbers);
167                         break;
168                 case CTSVC_DATA_EMAIL:
169                         ctsvc_get_data_info_email(stmt, (contacts_list_h)contact->emails);
170                         break;
171                 case CTSVC_DATA_PROFILE:
172                         ctsvc_get_data_info_profile(stmt, (contacts_list_h)contact->profiles);
173                         break;
174                 case CTSVC_DATA_RELATIONSHIP:
175                         ctsvc_get_data_info_relationship(stmt, (contacts_list_h)contact->relationships);
176                         break;
177                 case CTSVC_DATA_IMAGE:
178                         ctsvc_get_data_info_image(stmt, (contacts_list_h)contact->images);
179                         break;
180                 case CTSVC_DATA_COMPANY:
181                         ctsvc_get_data_info_company(stmt, (contacts_list_h)contact->company);
182                         break;
183                 case CTSVC_DATA_NOTE:
184                         ctsvc_get_data_info_note(stmt, (contacts_list_h)contact->note);
185                         break;
186                 case CTSVC_DATA_EXTENSION:
187                         ctsvc_get_data_info_extension(stmt, (contacts_list_h)contact->extensions);
188                         break;
189                 case CTSVC_DATA_SIP:
190                         ctsvc_get_data_info_sip(stmt, (contacts_list_h)contact->sips);
191                         break;
192                 default:
193                         ERR("Intenal : Not supported data type (%d)", datatype);
194                         break;
195                 }
196
197         } while (1 == ctsvc_stmt_step(stmt));
198
199         ctsvc_stmt_finalize(stmt);
200
201         return CONTACTS_ERROR_NONE;
202
203 }
204
205 static inline int __ctsvc_get_contact_grouprel(int contact_id, ctsvc_contact_s *contact)
206 {
207         CTS_FN_CALL;
208         int ret;
209         ctsvc_group_relation_s *grouprel;
210         cts_stmt stmt = NULL;
211         char query[CTS_SQL_MAX_LEN] = {0};
212         char *temp;
213
214         snprintf(query, sizeof(query),
215                         "SELECT group_id, contact_id, group_name "
216                         " FROM "CTSVC_DB_VIEW_GROUP_RELATION" WHERE contact_id = %d", contact_id);
217
218         ret = ctsvc_query_prepare(query, &stmt);
219         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
220
221         while (1 /*CTS_TRUE */ == ctsvc_stmt_step(stmt)) {
222                 contacts_record_create(_contacts_group_relation._uri, (contacts_record_h*)&grouprel);
223
224                 if (grouprel) {
225                         grouprel->group_id = ctsvc_stmt_get_int(stmt, 0);
226                         grouprel->id = grouprel->group_id;
227                         grouprel->contact_id = ctsvc_stmt_get_int(stmt, 1);
228                         temp = ctsvc_stmt_get_text(stmt, 2);
229                         grouprel->group_name = SAFE_STRDUP(temp);
230
231                         ctsvc_list_prepend((contacts_list_h)contact->grouprelations, (contacts_record_h)grouprel);
232                 }
233         }
234
235         ctsvc_stmt_finalize(stmt);
236         ctsvc_list_reverse((contacts_list_h)contact->grouprelations);
237         return CONTACTS_ERROR_NONE;
238 }
239
240 static int __ctsvc_db_contact_get_record(int id, contacts_record_h *out_record)
241 {
242         int ret;
243         contacts_record_h record;
244         ctsvc_contact_s *contact;
245
246         RETV_IF(NULL == out_record, CONTACTS_ERROR_INVALID_PARAMETER);
247         *out_record = NULL;
248
249         contacts_record_create(_contacts_contact._uri, &record);
250         contact = (ctsvc_contact_s*)record;
251         ret = __ctsvc_db_get_contact_base_info(id, contact);
252         if (CONTACTS_ERROR_NONE != ret) {
253                 ERR("__ctsvc_db_get_contact_base_info(ALL) Fail(%d)", ret);
254                 contacts_record_destroy(record, true);
255                 return ret;
256         }
257
258         ret = __ctsvc_db_get_data(id, contact);
259         if (CONTACTS_ERROR_NONE != ret && CONTACTS_ERROR_NO_DATA != ret) {
260                 ERR("ctsvc_get_data_info Fail(%d)", ret);
261                 contacts_record_destroy(record, true);
262                 return ret;
263         }
264
265         ret = __ctsvc_get_contact_grouprel(id, contact);
266         if (CONTACTS_ERROR_NONE != ret) {
267                 ERR("ctsvc_get_group_relations Fail(%d)", ret);
268                 contacts_record_destroy(record, true);
269                 return ret;
270         }
271
272         *out_record = record;
273
274         return CONTACTS_ERROR_NONE;
275 }
276
277 static int __ctsvc_db_contact_delete_record(int id)
278 {
279         return ctsvc_db_contact_delete(id);
280 }
281
282 static inline int __ctsvc_contact_update_data(ctsvc_contact_s *contact)
283 {
284         int ret;
285
286         if (contact->name) {
287                 ret = ctsvc_contact_update_data_name((contacts_list_h)contact->name, contact->id, false);
288                 if (CONTACTS_ERROR_NONE != ret) {
289                         ERR("ctsvc_contact_update_data_name() Fail(%d)", ret);
290                         return ret;
291                 }
292         }
293
294         if (contact->company) {
295                 ret = ctsvc_contact_update_data_company((contacts_list_h)contact->company, contact->id, false);
296                 if (CONTACTS_ERROR_NONE != ret) {
297                         ERR("ctsvc_contact_update_data_company() Fail(%d)", ret);
298                         return ret;
299                 }
300         }
301
302         if (contact->note) {
303                 ret = ctsvc_contact_update_data_note((contacts_list_h)contact->note, contact->id, false);
304                 if (CONTACTS_ERROR_NONE != ret) {
305                         ERR("ctsvc_contact_update_data_note() Fail(%d)", ret);
306                         return ret;
307                 }
308         }
309
310         if (contact->events) {
311                 ret = ctsvc_contact_update_data_event((contacts_list_h)contact->events, contact->id, false);
312                 if (CONTACTS_ERROR_NONE != ret) {
313                         ERR("ctsvc_contact_update_data_events() Fail(%d)", ret);
314                         return ret;
315                 }
316         }
317
318         if (contact->messengers) {
319                 ret = ctsvc_contact_update_data_messenger((contacts_list_h)contact->messengers, contact->id, false);
320                 if (CONTACTS_ERROR_NONE != ret) {
321                         ERR("ctsvc_contact_update_data_messengers() Fail(%d)", ret);
322                         return ret;
323                 }
324         }
325
326         if (contact->postal_addrs) {
327                 ret = ctsvc_contact_update_data_address((contacts_list_h)contact->postal_addrs, contact->id, false);
328                 if (CONTACTS_ERROR_NONE != ret) {
329                         ERR("ctsvc_contact_update_data_address() Fail(%d)", ret);
330                         return ret;
331                 }
332         }
333
334         if (contact->urls) {
335                 ret = ctsvc_contact_update_data_url((contacts_list_h)contact->urls, contact->id, false);
336                 if (CONTACTS_ERROR_NONE != ret) {
337                         ERR("ctsvc_contact_update_data_url() Fail(%d)", ret);
338                         return ret;
339                 }
340         }
341
342         if (contact->nicknames) {
343                 ret = ctsvc_contact_update_data_nickname((contacts_list_h)contact->nicknames, contact->id, false);
344                 if (CONTACTS_ERROR_NONE != ret) {
345                         ERR("ctsvc_contact_update_data_nickname() Fail(%d)", ret);
346                         return ret;
347                 }
348         }
349
350         if (contact->numbers) {
351                 bool had_phonenumber;
352                 ret = ctsvc_contact_update_data_number((contacts_list_h)contact->numbers, contact->id, false, &had_phonenumber);
353                 if (CONTACTS_ERROR_NONE != ret) {
354                         ERR("ctsvc_contact_update_data_number() Fail(%d)", ret);
355                         return ret;
356                 }
357                 contact->has_phonenumber = had_phonenumber;
358         }
359
360         if (contact->emails) {
361                 bool had_email;
362                 ret = ctsvc_contact_update_data_email((contacts_list_h)contact->emails, contact->id, false, &had_email);
363                 if (CONTACTS_ERROR_NONE != ret) {
364                         ERR("ctsvc_contact_update_data_email() Fail(%d)", ret);
365                         return ret;
366                 }
367                 contact->has_email = had_email;
368         }
369
370         if (contact->profiles) {
371                 ret = ctsvc_contact_update_data_profile((contacts_list_h)contact->profiles, contact->id, false);
372                 if (CONTACTS_ERROR_NONE != ret) {
373                         ERR("ctsvc_contact_update_data_profile() Fail(%d)", ret);
374                         return ret;
375                 }
376         }
377
378         if (contact->relationships) {
379                 ret = ctsvc_contact_update_data_relationship((contacts_list_h)contact->relationships, contact->id, false);
380                 if (CONTACTS_ERROR_NONE != ret) {
381                         ERR("ctsvc_contact_update_data_relationship() Fail(%d)", ret);
382                         return ret;
383                 }
384         }
385
386         if (contact->images) {
387                 ret = ctsvc_contact_update_data_image((contacts_list_h)contact->images, contact->id, false);
388                 if (CONTACTS_ERROR_NONE != ret) {
389                         ERR("ctsvc_contact_update_data_image() Fail(%d)", ret);
390                         return ret;
391                 }
392         }
393
394         if (contact->extensions) {
395                 ret = ctsvc_contact_update_data_extension((contacts_list_h)contact->extensions, contact->id, false);
396                 if (CONTACTS_ERROR_NONE != ret) {
397                         ERR("ctsvc_contact_update_data_extension() Fail(%d)", ret);
398                         return ret;
399                 }
400         }
401
402         if (contact->sips) {
403                 ret = ctsvc_contact_update_data_sip((contacts_list_h)contact->sips, contact->id, false);
404                 if (CONTACTS_ERROR_NONE != ret) {
405                         ERR("ctsvc_contact_update_data_sips() Fail(%d)", ret);
406                         return ret;
407                 }
408         }
409         return CONTACTS_ERROR_NONE;
410 }
411
412 static void __ctsvc_contact_check_default_data(ctsvc_contact_s *contact)
413 {
414         if (contact->numbers)
415                 contact->has_phonenumber = ctsvc_contact_check_default_number((contacts_list_h)contact->numbers);
416         if (contact->emails)
417                 contact->has_email = ctsvc_contact_check_default_email((contacts_list_h)contact->emails);
418         if (contact->images)
419                 ctsvc_contact_check_default_image((contacts_list_h)contact->images);
420         if (contact->postal_addrs)
421                 ctsvc_contact_check_default_address((contacts_list_h)contact->postal_addrs);
422 }
423
424 static inline int __ctsvc_contact_update_grouprel(int contact_id, contacts_list_h group_list)
425 {
426         CTS_FN_CALL;
427         ctsvc_group_relation_s *grouprel;
428         ctsvc_list_s *list = (ctsvc_list_s*)group_list;
429         int rel_changed = 0;
430         int count;
431         int ret;
432         GList *cursor;
433
434         RETV_IF(NULL == group_list, CONTACTS_ERROR_INVALID_PARAMETER);
435
436         for (cursor = list->deleted_records; cursor; cursor = cursor->next) {
437                 grouprel = cursor->data;
438                 ret = ctsvc_group_remove_contact_in_transaction(grouprel->group_id, contact_id);
439                 if (0 < ret)
440                         rel_changed += ret;
441         }
442
443         ret = contacts_list_get_count(group_list, &count);
444         if (0 == count)
445                 return CONTACTS_ERROR_NONE;
446
447         contacts_list_first(group_list);
448         do {
449                 contacts_list_get_current_record_p(group_list, (contacts_record_h*)&grouprel);
450                 if (NULL == grouprel)
451                         continue;
452
453                 RETVM_IF(grouprel->group_id <= 0, CONTACTS_ERROR_INVALID_PARAMETER, "group_id(%d) invalid", grouprel->group_id);
454                 if (grouprel->group_id) {
455                         ret = ctsvc_group_add_contact_in_transaction(grouprel->group_id, contact_id);
456                         RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_db_group_set_relation() Fail(%d)", ret);
457                         if (0 < ret)
458                                 rel_changed += ret;
459                 }
460         } while (CONTACTS_ERROR_NONE == contacts_list_next(group_list));
461
462         if (rel_changed)
463                 return rel_changed;
464         else
465                 return CONTACTS_ERROR_NONE;
466 }
467
468 static bool __ctsvc_contact_check_token(char *src, char *dest, int len)
469 {
470         bool had = false;
471         int i = 0;
472
473         for (i = 0; i < len; i++) {
474                 if (src[i] == '@' || src[i] == '.') {
475                         dest[i] = ' ';
476                         had = true;
477                 } else {
478                         dest[i] = src[i];
479                 }
480         }
481         dest[i] = '\0';
482
483         return had;
484 }
485
486 /* Make search data by number, email, nicknames, address, note, messenger, relationship, company */
487 static inline int __ctsvc_contact_make_search_data(ctsvc_contact_s *contact,
488                 char **search_number, char **search_data)
489 {
490         int len = 0;
491
492         char *number = NULL;
493         char *data = NULL;
494         char *temp_number = NULL;
495         char *temp_data = NULL;
496         int buf_size = 0;
497
498         RETV_IF(NULL == contact, CONTACTS_ERROR_NO_DATA);
499
500         if (contact->numbers) {
501                 contacts_list_h number_list = (contacts_list_h)contact->numbers;
502                 ctsvc_number_s *number_record;
503                 contacts_list_first(number_list);
504                 do {
505                         contacts_list_get_current_record_p(number_list, (contacts_record_h*)&number_record);
506                         if (number_record && number_record->cleaned) {
507                                 buf_size = SAFE_STRLEN(number) + SAFE_STRLEN(number_record->cleaned) + SAFE_STRLEN(number_record->normalized) + 3;
508                                 temp_number = calloc(1, buf_size);
509                                 if (NULL == temp_number) {
510                                         ERR("calloc() Fail");
511                                         free(number);
512                                         return CONTACTS_ERROR_OUT_OF_MEMORY;
513                                 }
514
515                                 if (number)
516                                         snprintf(temp_number, buf_size, "%s %s %s", SAFE_STR(number), number_record->cleaned, number_record->normalized);
517                                 else
518                                         snprintf(temp_number, buf_size, "%s %s", number_record->cleaned, number_record->normalized);
519                                 free(number);
520                                 number = temp_number;
521                         }
522                 } while (CONTACTS_ERROR_NONE == contacts_list_next(number_list));
523         }
524
525         if (contact->emails) {
526                 contacts_list_h email_list = (contacts_list_h)contact->emails;
527                 ctsvc_email_s *email;
528                 contacts_list_first(email_list);
529                 do {
530                         contacts_list_get_current_record_p(email_list, (contacts_record_h*)&email);
531                         if (email && email->email_addr) {
532                                 int len = strlen(email->email_addr);
533                                 char temp[len+1];
534                                 bool had = __ctsvc_contact_check_token(email->email_addr, temp, len);
535
536                                 buf_size = SAFE_STRLEN(data) + SAFE_STRLEN(email->email_addr)
537                                         * (had ? 2 : 1) + 4;
538                                 temp_data = calloc(1, buf_size);
539                                 if (NULL == temp_data) {
540                                         ERR("calloc() Fail");
541                                         free(data);
542                                         free(number);
543                                         return CONTACTS_ERROR_OUT_OF_MEMORY;
544                                 }
545
546                                 if (data) {
547                                         snprintf(temp_data, buf_size, "%s %s %s", data, email->email_addr,
548                                                         (had ? temp : ""));
549                                 } else {
550                                         snprintf(temp_data, buf_size, "%s %s", email->email_addr,
551                                                         (had ? temp : ""));
552                                 }
553                                 free(data);
554                                 data = temp_data;
555                         }
556                 } while (CONTACTS_ERROR_NONE == contacts_list_next(email_list));
557         }
558
559         if (contact->nicknames) {
560                 contacts_list_h nickname_list = (contacts_list_h)contact->nicknames;
561                 ctsvc_nickname_s *nickname;
562                 contacts_list_first(nickname_list);
563                 do {
564                         contacts_list_get_current_record_p(nickname_list, (contacts_record_h*)&nickname);
565                         if (nickname && nickname->nickname) {
566                                 int len = strlen(nickname->nickname);
567                                 char temp[len+1];
568                                 bool had = __ctsvc_contact_check_token(nickname->nickname, temp, len);
569
570                                 buf_size = SAFE_STRLEN(data) + SAFE_STRLEN(nickname->nickname) * (had ? 2 : 1) + 4;
571                                 temp_data = calloc(1, buf_size);
572                                 if (NULL == temp_data) {
573                                         ERR("calloc() Fail");
574                                         free(data);
575                                         free(number);
576                                         return CONTACTS_ERROR_OUT_OF_MEMORY;
577                                 }
578
579                                 if (data)
580                                         snprintf(temp_data, buf_size, "%s %s %s", data, nickname->nickname, (had ? temp : ""));
581                                 else
582                                         snprintf(temp_data, buf_size, "%s %s", nickname->nickname, (had ? temp : ""));
583                                 free(data);
584                                 data = temp_data;
585                         }
586                 } while (CONTACTS_ERROR_NONE == contacts_list_next(nickname_list));
587         }
588
589         if (contact->postal_addrs) {
590                 contacts_list_h address_list = (contacts_list_h)contact->postal_addrs;
591                 ctsvc_address_s *address;
592                 contacts_list_first(address_list);
593                 do {
594                         contacts_list_get_current_record_p(address_list, (contacts_record_h*)&address);
595                         if (address) {
596                                 bool had;
597                                 int str_len = SAFE_STRLEN(address->country)
598                                         + SAFE_STRLEN(address->pobox)
599                                         + SAFE_STRLEN(address->postalcode)
600                                         + SAFE_STRLEN(address->region)
601                                         + SAFE_STRLEN(address->locality)
602                                         + SAFE_STRLEN(address->street)
603                                         + SAFE_STRLEN(address->extended);
604                                 len = 0;
605                                 buf_size = SAFE_STRLEN(data)
606                                         + str_len * 2 + 16;
607                                 temp_data = calloc(1, buf_size);
608                                 if (NULL == temp_data) {
609                                         ERR("calloc() Fail");
610                                         free(data);
611                                         free(number);
612                                         return CONTACTS_ERROR_OUT_OF_MEMORY;
613                                 }
614
615                                 char temp[str_len+1];
616
617                                 if (data)
618                                         len += snprintf(temp_data + len, buf_size - len, "%s ", data);
619
620                                 if (address->country) {
621                                         had = __ctsvc_contact_check_token(address->country, temp, SAFE_STRLEN(address->country));
622                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", address->country, had ? temp : "");
623                                 }
624                                 if (address->pobox) {
625                                         had = __ctsvc_contact_check_token(address->pobox, temp, SAFE_STRLEN(address->pobox));
626                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", address->pobox, had ? temp : "");
627                                 }
628                                 if (address->postalcode) {
629                                         had = __ctsvc_contact_check_token(address->postalcode, temp, SAFE_STRLEN(address->postalcode));
630                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", address->postalcode, had ? temp : "");
631                                 }
632                                 if (address->region) {
633                                         had = __ctsvc_contact_check_token(address->region, temp, SAFE_STRLEN(address->region));
634                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", address->region, had ? temp : "");
635                                 }
636                                 if (address->locality) {
637                                         had = __ctsvc_contact_check_token(address->locality, temp, SAFE_STRLEN(address->locality));
638                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", address->locality, had ? temp : "");
639                                 }
640                                 if (address->street) {
641                                         had = __ctsvc_contact_check_token(address->street, temp, SAFE_STRLEN(address->street));
642                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", address->street, had ? temp : "");
643                                 }
644                                 if (address->extended) {
645                                         had = __ctsvc_contact_check_token(address->extended, temp, SAFE_STRLEN(address->extended));
646                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", address->extended, had ? temp : "");
647                                 }
648                                 free(data);
649                                 data = temp_data;
650                         }
651                 } while (CONTACTS_ERROR_NONE == contacts_list_next(address_list));
652         }
653
654         if (contact->note) {
655                 contacts_list_h note_list = (contacts_list_h)contact->note;
656                 ctsvc_note_s *note;
657                 contacts_list_first(note_list);
658                 do {
659                         contacts_list_get_current_record_p(note_list, (contacts_record_h*)&note);
660                         if (note && note->note) {
661                                 int len = strlen(note->note);
662                                 char temp[len+1];
663                                 bool had = __ctsvc_contact_check_token(note->note, temp, len);
664
665                                 buf_size = SAFE_STRLEN(data) + SAFE_STRLEN(note->note) * (had ? 2 : 1) + 4;
666                                 temp_data = calloc(1, buf_size);
667                                 if (NULL == temp_data) {
668                                         ERR("calloc() Fail");
669                                         free(data);
670                                         free(number);
671                                         return CONTACTS_ERROR_OUT_OF_MEMORY;
672                                 }
673
674                                 if (data) {
675                                         snprintf(temp_data, buf_size, "%s %s %s", data, note->note,
676                                                         (had ? temp : ""));
677                                 } else {
678                                         snprintf(temp_data, buf_size, "%s %s", note->note,
679                                                         (had ? temp : ""));
680                                 }
681                                 free(data);
682                                 data = temp_data;
683                         }
684                 } while (CONTACTS_ERROR_NONE == contacts_list_next(note_list));
685         }
686
687         if (contact->messengers) {
688                 contacts_list_h messenger_list = (contacts_list_h)contact->messengers;
689                 ctsvc_messenger_s *messenger;
690                 contacts_list_first(messenger_list);
691                 do {
692                         contacts_list_get_current_record_p(messenger_list, (contacts_record_h*)&messenger);
693                         if (messenger && messenger->im_id) {
694                                 int len = strlen(messenger->im_id);
695                                 char temp[len+1];
696                                 bool had = __ctsvc_contact_check_token(messenger->im_id, temp, len);
697
698                                 buf_size = SAFE_STRLEN(data) + SAFE_STRLEN(messenger->im_id) * (had ? 2 : 1) + 4;
699                                 temp_data = calloc(1, buf_size);
700                                 if (NULL == temp_data) {
701                                         ERR("calloc() Fail");
702                                         free(data);
703                                         free(number);
704                                         return CONTACTS_ERROR_OUT_OF_MEMORY;
705                                 }
706
707                                 if (data) {
708                                         snprintf(temp_data, buf_size, "%s %s %s", data, messenger->im_id,
709                                                         (had ? temp : ""));
710                                 } else {
711                                         snprintf(temp_data, buf_size, "%s %s", messenger->im_id,
712                                                         (had ? temp : ""));
713                                 }
714                                 free(data);
715                                 data = temp_data;
716                         }
717                 } while (CONTACTS_ERROR_NONE == contacts_list_next(messenger_list));
718         }
719
720         if (contact->relationships) {
721                 contacts_list_h relationship_list = (contacts_list_h)contact->relationships;
722                 ctsvc_relationship_s *relationship;
723                 contacts_list_first(relationship_list);
724                 do {
725                         contacts_list_get_current_record_p(relationship_list, (contacts_record_h*)&relationship);
726                         if (relationship && relationship->name) {
727                                 int len = strlen(relationship->name);
728                                 char temp[len+1];
729                                 bool had = __ctsvc_contact_check_token(relationship->name, temp, len);
730
731                                 buf_size = SAFE_STRLEN(data) + SAFE_STRLEN(relationship->name) * (had ? 2 : 1) + 4;
732                                 temp_data = calloc(1, buf_size);
733                                 if (NULL == temp_data) {
734                                         ERR("calloc() Fail");
735                                         free(data);
736                                         free(number);
737                                         return CONTACTS_ERROR_OUT_OF_MEMORY;
738                                 }
739
740                                 if (data) {
741                                         snprintf(temp_data, buf_size, "%s %s %s", data, relationship->name,
742                                                         (had ? temp : ""));
743                                 } else {
744                                         snprintf(temp_data, buf_size, "%s %s", relationship->name,
745                                                         (had ? temp : ""));
746                                 }
747                                 free(data);
748                                 data = temp_data;
749                         }
750                 } while (CONTACTS_ERROR_NONE == contacts_list_next(relationship_list));
751         }
752
753         if (contact->company) {
754                 contacts_list_h company_list = (contacts_list_h)contact->company;
755                 ctsvc_company_s *company;
756                 contacts_list_first(company_list);
757                 do {
758                         contacts_list_get_current_record_p(company_list, (contacts_record_h*)&company);
759                         if (company) {
760                                 bool had;
761                                 int str_len = SAFE_STRLEN(company->name)
762                                         + SAFE_STRLEN(company->department)
763                                         + SAFE_STRLEN(company->job_title)
764                                         + SAFE_STRLEN(company->role)
765                                         + SAFE_STRLEN(company->assistant_name)
766                                         + SAFE_STRLEN(company->location)
767                                         + SAFE_STRLEN(company->description)
768                                         + SAFE_STRLEN(company->phonetic_name);
769                                 len = 0;
770                                 buf_size = SAFE_STRLEN(data) + str_len * 2 + 18;
771                                 temp_data = calloc(1, buf_size);
772                                 if (NULL == temp_data) {
773                                         ERR("calloc() Fail");
774                                         free(data);
775                                         free(number);
776                                         return CONTACTS_ERROR_OUT_OF_MEMORY;
777                                 }
778
779                                 char temp[str_len+1];
780
781                                 if (data)
782                                         len += snprintf(temp_data + len, buf_size - len, "%s ", data);
783                                 if (company->name) {
784                                         had = __ctsvc_contact_check_token(company->name, temp, SAFE_STRLEN(company->name));
785                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", company->name, had ? temp : "");
786                                 }
787                                 if (company->department) {
788                                         had = __ctsvc_contact_check_token(company->department, temp, SAFE_STRLEN(company->department));
789                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", company->department, had ? temp : "");
790                                 }
791                                 if (company->job_title) {
792                                         had = __ctsvc_contact_check_token(company->job_title, temp, SAFE_STRLEN(company->job_title));
793                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", company->job_title, had ? temp : "");
794                                 }
795                                 if (company->role) {
796                                         had = __ctsvc_contact_check_token(company->role, temp, SAFE_STRLEN(company->role));
797                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", company->role, had ? temp : "");
798                                 }
799                                 if (company->assistant_name) {
800                                         had = __ctsvc_contact_check_token(company->assistant_name, temp, SAFE_STRLEN(company->assistant_name));
801                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", company->assistant_name, had ? temp : "");
802                                 }
803                                 if (company->location) {
804                                         had = __ctsvc_contact_check_token(company->location, temp, SAFE_STRLEN(company->location));
805                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", company->location, had ? temp : "");
806                                 }
807                                 if (company->description) {
808                                         had = __ctsvc_contact_check_token(company->description, temp, SAFE_STRLEN(company->description));
809                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", company->description, had ? temp : "");
810                                 }
811                                 if (company->phonetic_name) {
812                                         had = __ctsvc_contact_check_token(company->phonetic_name, temp, SAFE_STRLEN(company->phonetic_name));
813                                         len += snprintf(temp_data + len, buf_size - len, "%s %s ", company->phonetic_name, had ? temp : "");
814                                 }
815
816                                 free(data);
817                                 data = temp_data;
818                         }
819                 } while (CONTACTS_ERROR_NONE == contacts_list_next(company_list));
820         }
821
822         *search_number = number;
823         if (data)
824                 *search_data = data;
825
826         return CONTACTS_ERROR_NONE;
827 }
828
829 static inline int __ctsvc_contact_refresh_lookup_data(int contact_id, ctsvc_contact_s *contact)
830 {
831         CTS_FN_CALL;
832         int ret, len = 0, temp_len = 0;
833         char query[CTS_SQL_MAX_LEN] = {0};
834
835         snprintf(query, sizeof(query), "DELETE FROM %s WHERE contact_id = %d",
836                         CTS_TABLE_NAME_LOOKUP, contact_id);
837         ret = ctsvc_query_exec(query);
838         if (CONTACTS_ERROR_NONE != ret) {
839                 ERR("ctsvc_query_exec() Fail(%d)", ret);
840                 return ret;
841         }
842
843         snprintf(query, sizeof(query), "DELETE FROM %s WHERE contact_id = %d",
844                         CTS_TABLE_PHONE_LOOKUP, contact_id);
845         ret = ctsvc_query_exec(query);
846         if (CONTACTS_ERROR_NONE != ret) {
847                 ERR("ctsvc_query_exec() Fail(%d)", ret);
848                 return ret;
849         }
850
851         if (contact == NULL)
852                 return CONTACTS_ERROR_NO_DATA;
853
854         if (contact->name) {
855                 contacts_list_h name_list = (contacts_list_h)contact->name;
856                 ctsvc_name_s *name_record;
857                 cts_stmt stmt = NULL;
858                 char *temp_name = NULL;
859                 contacts_list_first(name_list);
860                 len = 0;
861                 /* name record of contact should be one */
862                 do {
863                         contacts_list_get_current_record_p(name_list, (contacts_record_h*)&name_record);
864                         if (name_record
865                                         && (name_record->last
866                                                 || name_record->first
867                                                 || name_record->addition
868                                                 || name_record->suffix)) {
869                                 char *normalized_name = NULL;
870
871                                 /*
872                                  * Make reverse display name (Last name first)
873                                  * Default         : Prefix Last, First Middle(addition), Suffix
874                                  * Korean, Chinese : Prefix LastMiddleFirstSuffix
875                                  * Japanese        : Prefix Last Middle First Suffix
876                                  * reverse sort name does not include prefix
877                                  * But, if there is only prefix, reverse sort_name is prefix
878                                  */
879                                 /* make display name */
880                                 temp_len = SAFE_STRLEN(name_record->first)
881                                         + SAFE_STRLEN(name_record->addition)
882                                         + SAFE_STRLEN(name_record->last)
883                                         + SAFE_STRLEN(name_record->suffix)
884                                         + 1;
885                                 int reverse_lang_type = ctsvc_contact_get_name_language(name_record);
886                                 temp_name = calloc(1, temp_len);
887                                 if (NULL == temp_name) {
888                                         ERR("calloc() Fail");
889                                         return CONTACTS_ERROR_OUT_OF_MEMORY;
890                                 }
891
892                                 if (reverse_lang_type == CTSVC_LANG_KOREAN ||
893                                                 reverse_lang_type == CTSVC_LANG_CHINESE ||
894                                                 reverse_lang_type == CTSVC_LANG_JAPANESE) {
895                                         if (name_record->last)
896                                                 len += snprintf(temp_name + len, temp_len - len, "%s", name_record->last);
897                                         if (name_record->addition)
898                                                 len += snprintf(temp_name + len, temp_len - len, "%s", name_record->addition);
899                                         if (name_record->first)
900                                                 len += snprintf(temp_name + len, temp_len - len, "%s", name_record->first);
901                                         if (name_record->suffix)
902                                                 len += snprintf(temp_name + len, temp_len - len, "%s", name_record->suffix);
903                                 } else {
904                                         if (name_record->last)
905                                                 len += snprintf(temp_name + len, temp_len - len, "%s", name_record->last);
906                                         if (name_record->first)
907                                                 len += snprintf(temp_name + len, temp_len - len, "%s", name_record->first);
908                                         if (name_record->addition)
909                                                 len += snprintf(temp_name + len, temp_len - len, "%s", name_record->addition);
910                                         if (name_record->suffix)
911                                                 len += snprintf(temp_name + len, temp_len - len, "%s", name_record->suffix);
912                                 }
913
914                                 ctsvc_normalize_str(temp_name, &normalized_name);
915                                 snprintf(query, sizeof(query), "INSERT INTO %s(data_id, contact_id, name, type) "
916                                                 "VALUES(%d, %d, ?, %d)",        CTS_TABLE_NAME_LOOKUP, name_record->id,
917                                                 contact_id, 0);
918
919                                 ret = ctsvc_query_prepare(query, &stmt);
920                                 if (NULL == stmt) {
921                                         ERR("ctsvc_query_prepare() Fail(%d)", ret);
922                                         free(temp_name);
923                                         free(normalized_name);
924                                         return ret;
925                                 }
926
927                                 if (normalized_name)
928                                         ctsvc_stmt_bind_text(stmt, 1, normalized_name);
929
930                                 ret = ctsvc_stmt_step(stmt);
931
932                                 free(temp_name);
933                                 free(normalized_name);
934
935                                 ctsvc_stmt_finalize(stmt);
936
937                                 if (CONTACTS_ERROR_NONE != ret) {
938                                         ERR("ctsvc_stmt_step() Fail(%d)", ret);
939                                         return ret;
940                                 }
941                                 break;
942                         }
943                 } while (CONTACTS_ERROR_NONE == contacts_list_next(name_list));
944         }
945
946         if (contact->numbers) {
947                 contacts_list_h number_list = (contacts_list_h)contact->numbers;
948                 cts_stmt stmt = NULL;
949                 ctsvc_number_s *number_record;
950                 contacts_list_first(number_list);
951                 len = 0;
952                 do {
953                         contacts_list_get_current_record_p(number_list, (contacts_record_h*)&number_record);
954                         if (number_record && number_record->number) {
955                                 if (NULL == number_record->cleaned)
956                                         continue;
957
958                                 /* actually phone_lookup minmatch is not used */
959                                 snprintf(query, sizeof(query), "INSERT INTO %s(data_id, contact_id, number, min_match) "
960                                                 "VALUES(%d, %d, ?, ?)", CTS_TABLE_PHONE_LOOKUP, number_record->id,
961                                                 contact_id);
962
963                                 ret = ctsvc_query_prepare(query, &stmt);
964                                 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
965
966                                 if (*number_record->cleaned)
967                                         ctsvc_stmt_bind_text(stmt, 1, number_record->cleaned);
968                                 ret = ctsvc_stmt_step(stmt);
969                                 if (CONTACTS_ERROR_NONE != ret) {
970                                         ERR("ctsvc_stmt_step() Fail(%d)", ret);
971                                         ctsvc_stmt_finalize(stmt);
972                                         return ret;
973                                 }
974                                 if (number_record->normalized && STRING_EQUAL != strcmp(number_record->cleaned, number_record->normalized)) {
975                                         ctsvc_stmt_reset(stmt);
976                                         if (*number_record->normalized)
977                                                 ctsvc_stmt_bind_text(stmt, 1, number_record->normalized);
978                                         ret = ctsvc_stmt_step(stmt);
979                                         if (CONTACTS_ERROR_NONE != ret) {
980                                                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
981                                                 ctsvc_stmt_finalize(stmt);
982                                                 return ret;
983                                         }
984                                 }
985                                 ctsvc_stmt_finalize(stmt);
986                         }
987                 } while (CONTACTS_ERROR_NONE == contacts_list_next(number_list));
988         }
989
990         if (contact->nicknames) {
991                 contacts_list_h nickname_list = (contacts_list_h)contact->nicknames;
992                 cts_stmt stmt = NULL;
993                 ctsvc_nickname_s *nickname;
994                 contacts_list_first(nickname_list);
995                 do {
996                         contacts_list_get_current_record_p(nickname_list, (contacts_record_h*)&nickname);
997                         if (nickname && nickname->nickname) {
998                                 char *normalized_nickname = NULL;
999                                 ctsvc_normalize_str(nickname->nickname, &normalized_nickname);
1000                                 snprintf(query, sizeof(query), "INSERT INTO %s(data_id, contact_id, name, type) "
1001                                                 "VALUES(%d, %d, ?, %d)",        CTS_TABLE_NAME_LOOKUP, nickname->id,
1002                                                 contact_id,  0);
1003
1004                                 ret = ctsvc_query_prepare(query, &stmt);
1005                                 if (NULL == stmt) {
1006                                         ERR("ctsvc_query_prepare() Fail(%d)", ret);
1007                                         free(normalized_nickname);
1008                                         return ret;
1009                                 }
1010
1011                                 if (normalized_nickname && *normalized_nickname)
1012                                         ctsvc_stmt_bind_text(stmt, 1, normalized_nickname);
1013
1014                                 ret = ctsvc_stmt_step(stmt);
1015
1016                                 free(normalized_nickname);
1017
1018                                 ctsvc_stmt_finalize(stmt);
1019
1020                                 if (CONTACTS_ERROR_NONE != ret) {
1021                                         ERR("ctsvc_stmt_step() Fail(%d)", ret);
1022                                         return ret;
1023                                 }
1024                         }
1025                 } while (CONTACTS_ERROR_NONE == contacts_list_next(nickname_list));
1026         }
1027
1028         return CONTACTS_ERROR_NONE;
1029 }
1030
1031 static inline int __ctsvc_contact_update_search_data(int contact_id, bool need_refresh_lookup_data)
1032 {
1033         int ret;
1034         cts_stmt stmt = NULL;
1035         char query[CTS_SQL_MAX_LEN] = {0};
1036         char *search_name = NULL;
1037         char *search_number = NULL;
1038         char *search_data = NULL;
1039         ctsvc_contact_s *contact = NULL;
1040
1041         ret = ctsvc_begin_trans();
1042         RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
1043
1044         ret = ctsvc_db_contact_get(contact_id, (contacts_record_h*)&contact);
1045         if (CONTACTS_ERROR_NO_DATA == ret) {
1046                 int r;
1047                 snprintf(query, sizeof(query), "DELETE FROM %s WHERE contact_id = %d",
1048                                 CTS_TABLE_SEARCH_INDEX, contact_id);
1049                 r = ctsvc_query_exec(query);
1050                 if (CONTACTS_ERROR_NONE != r) {
1051                         ERR("ctsvc_query_exec() Fail(%d)", r);
1052                         ctsvc_end_trans(false);
1053                         return r;
1054                 }
1055                 ctsvc_end_trans(false);
1056                 return ret;
1057         } else if (CONTACTS_ERROR_NONE != ret) {
1058                 ERR("ctsvc_db_contact_get() Fail(%d)", ret);
1059                 ctsvc_end_trans(false);
1060                 return ret;
1061         }
1062
1063         ret = ctsvc_contact_make_search_name(contact, &search_name);
1064         if (CONTACTS_ERROR_NONE != ret) {
1065                 ERR("ctsvc_contact_make_search_name() Fail(%d)", ret);
1066                 contacts_record_destroy((contacts_record_h)contact, true);
1067                 ctsvc_end_trans(false);
1068                 return ret;
1069         }
1070
1071         ret = __ctsvc_contact_make_search_data(contact, &search_number, &search_data);
1072         if (CONTACTS_ERROR_NONE != ret) {
1073                 ERR("__ctsvc_contact_make_search_data() Fail(%d)", ret);
1074                 contacts_record_destroy((contacts_record_h)contact, true);
1075                 ctsvc_end_trans(false);
1076                 free(search_name);
1077                 return ret;
1078         }
1079
1080         snprintf(query, sizeof(query),
1081                         "UPDATE %s SET name=?, number=?, data=? "
1082                         "WHERE contact_id = %d",
1083                         CTS_TABLE_SEARCH_INDEX, contact_id);
1084
1085         ret = ctsvc_query_prepare(query, &stmt);
1086         if (NULL == stmt) {
1087                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
1088                 contacts_record_destroy((contacts_record_h)contact, true);
1089                 ctsvc_end_trans(false);
1090                 free(search_name);
1091                 free(search_number);
1092                 free(search_data);
1093                 return ret;
1094         }
1095
1096         if (search_name)
1097                 ctsvc_stmt_bind_text(stmt, 1, search_name);
1098         if (search_number)
1099                 ctsvc_stmt_bind_text(stmt, 2, search_number);
1100         if (search_data)
1101                 ctsvc_stmt_bind_text(stmt, 3, search_data);
1102
1103         ret = ctsvc_stmt_step(stmt);
1104
1105         free(search_name);
1106         free(search_number);
1107         free(search_data);
1108
1109         if (CONTACTS_ERROR_NONE != ret) {
1110                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
1111                 contacts_record_destroy((contacts_record_h)contact, true);
1112                 ctsvc_stmt_finalize(stmt);
1113                 ctsvc_end_trans(false);
1114                 return ret;
1115         }
1116         ctsvc_stmt_finalize(stmt);
1117
1118         if (need_refresh_lookup_data) {
1119                 /* update phone_lookup, name_lookup */
1120                 ret = __ctsvc_contact_refresh_lookup_data(contact_id, contact);
1121                 if (CONTACTS_ERROR_NONE != ret) {
1122                         ERR("__ctsvc_contact_refresh_lookup_data() Fail(%d)", ret);
1123                         contacts_record_destroy((contacts_record_h)contact, true);
1124                         ctsvc_end_trans(false);
1125                         return ret;
1126                 }
1127         }
1128
1129         contacts_record_destroy((contacts_record_h)contact, true);
1130
1131         ret = ctsvc_end_trans(true);
1132         RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_end_trans() Fail(%d)", ret);
1133
1134         return CONTACTS_ERROR_NONE;
1135 }
1136
1137 static bool __ctsvc_list_check_dirty(ctsvc_list_s *list)
1138 {
1139         if (list) {
1140                 if (list->deleted_records)
1141                         return true;
1142
1143                 GList *c = NULL;
1144                 for (c = list->records; c; c = c->next) {
1145                         ctsvc_record_s *s_record = c->data;
1146                         int i;
1147                         unsigned int property_info_count = 0;
1148                         const property_info_s *property_info = ctsvc_view_get_all_property_infos(s_record->view_uri, &property_info_count);
1149                         for (i = 0; i < property_info_count; i++) {
1150                                 bool ret = ctsvc_record_check_property_flag(s_record,
1151                                                 property_info[i].property_id, CTSVC_PROPERTY_FLAG_DIRTY);
1152                                 if (ret)
1153                                         return true;
1154                         }
1155                 }
1156         }
1157         return false;
1158 }
1159
1160 static bool __ctsvc_get_need_refresh_lookup_data(ctsvc_contact_s *contact)
1161 {
1162         if (__ctsvc_list_check_dirty(contact->name))
1163                 return true;
1164         if (__ctsvc_list_check_dirty(contact->numbers))
1165                 return true;
1166         if (__ctsvc_list_check_dirty(contact->nicknames))
1167                 return true;
1168         return false;
1169 }
1170
1171 static int __ctsvc_db_contact_update_record(contacts_record_h record)
1172 {
1173         int ret, len = 0;
1174         int rel_changed = 0;
1175         int version;
1176         char *set = NULL;
1177         char query[CTS_SQL_MAX_LEN] = {0};
1178         GSList *bind_text = NULL;
1179         GSList *cursor = NULL;
1180         ctsvc_contact_s *contact = (ctsvc_contact_s*)record;
1181         bool is_invalid = false;
1182         int current_version = 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 changed_ver FROM "CTS_TABLE_CONTACTS" "
1189                         "WHERE contact_id = %d AND deleted = 0", contact->id);
1190         ret = ctsvc_query_get_first_int_result(query, &current_version);
1191         if (CONTACTS_ERROR_NONE != ret) {
1192                 ERR("The index(%d) is Invalid. %d Record(s) is(are) found", contact->id, ret);
1193                 ctsvc_end_trans(false);
1194                 return ret;
1195         }
1196
1197         if (false == ctsvc_have_ab_write_permission(contact->addressbook_id, false)) {
1198                 ERR("No permission in this addresbook_id(%d)", contact->addressbook_id);
1199                 ctsvc_end_trans(false);
1200                 return CONTACTS_ERROR_PERMISSION_DENIED;
1201         }
1202
1203         if (current_version != contact->changed_ver)
1204                 is_invalid = true;
1205         __ctsvc_contact_check_default_data(contact);
1206
1207         /* check lookup data is dirty */
1208         bool need_update_lookup = __ctsvc_get_need_refresh_lookup_data(contact);
1209
1210         /* update data */
1211         ret = __ctsvc_contact_update_data(contact);
1212         if (CONTACTS_ERROR_NONE != ret) {
1213                 ERR("__ctsvc_contact_update_data() Fail(%d)", ret);
1214                 ctsvc_end_trans(false);
1215                 return ret;
1216         }
1217
1218         if (contact->grouprelations) {
1219                 rel_changed = __ctsvc_contact_update_grouprel(contact->id, (contacts_list_h)contact->grouprelations);
1220                 if (rel_changed < CONTACTS_ERROR_NONE) {
1221                         ERR("cts_update_contact_grouprel() Fail(%d)", rel_changed);
1222                         ctsvc_end_trans(false);
1223                         return rel_changed;
1224                 }
1225         }
1226
1227         /* thumbnail */
1228         if (contact->images) {
1229                 int ret = CONTACTS_ERROR_NONE;
1230                 int count = 0;
1231                 ctsvc_image_s *image;
1232
1233                 contacts_list_get_count((contacts_list_h)contact->images, &count);
1234                 if (count) {
1235                         contacts_list_first((contacts_list_h)contact->images);
1236                         do {
1237                                 ret = contacts_list_get_current_record_p((contacts_list_h)contact->images, (contacts_record_h*)&image);
1238                                 if (CONTACTS_ERROR_NONE != ret) {
1239                                         ERR("contacts_list_get_current_record_p() Fail(%d)", ret);
1240                                         ctsvc_end_trans(false);
1241                                         return CONTACTS_ERROR_DB;
1242                                 }
1243
1244                                 if (image->is_default)
1245                                         break;
1246                         } while (CONTACTS_ERROR_NONE == contacts_list_next((contacts_list_h)contact->images));
1247
1248                         if ((NULL == contact->image_thumbnail_path && image->path) ||
1249                                         (contact->image_thumbnail_path && NULL == image->path) ||
1250                                         (contact->image_thumbnail_path && image->path && (STRING_EQUAL != strcmp(contact->image_thumbnail_path, image->path)))) {
1251                                 ctsvc_record_set_property_flag((ctsvc_record_s*)contact, _contacts_contact.image_thumbnail_path, CTSVC_PROPERTY_FLAG_DIRTY);
1252
1253                                 if (ctsvc_contact_check_image_location(image->path))
1254                                         contact->image_thumbnail_path = SAFE_STRDUP(image->path + strlen(CTSVC_CONTACT_IMG_FULL_LOCATION) + 1);
1255                                 else
1256                                         contact->image_thumbnail_path = SAFE_STRDUP(image->path);
1257                         }
1258                 } else if (contact->image_thumbnail_path) {
1259                         free(contact->image_thumbnail_path);
1260                         contact->image_thumbnail_path = NULL;
1261                         bool is_changed = ctsvc_record_check_property_flag((ctsvc_record_s*)contact, _contacts_contact.image_thumbnail_path, CTSVC_PROPERTY_FLAG_DIRTY);
1262                         if ((false == is_changed && false == is_invalid) || (is_changed && false == is_invalid)) {
1263                                 ctsvc_record_set_property_flag((ctsvc_record_s*)contact, _contacts_contact.image_thumbnail_path, CTSVC_PROPERTY_FLAG_DIRTY);
1264                         } else {
1265                                 if (((ctsvc_record_s*)record)->properties_flags) {
1266                                         int index = _contacts_contact.image_thumbnail_path & 0x000000FF;
1267                                         ((ctsvc_record_s*)record)->properties_flags[index] = 0;
1268                                 }
1269                         }
1270                 }
1271         }
1272
1273         if (is_invalid) {
1274                 ctsvc_contact_s *temp_contact;
1275                 contacts_record_create(_contacts_contact._uri, (contacts_record_h*)&temp_contact);
1276                 ret = __ctsvc_db_get_data(contact->id, temp_contact);
1277                 ctsvc_contact_make_display_name(temp_contact);
1278
1279                 FREEandSTRDUP(contact->display_name, temp_contact->display_name);
1280                 FREEandSTRDUP(contact->reverse_display_name, temp_contact->reverse_display_name);
1281                 FREEandSTRDUP(contact->sort_name, temp_contact->sort_name);
1282                 FREEandSTRDUP(contact->reverse_sort_name, temp_contact->reverse_sort_name);
1283                 FREEandSTRDUP(contact->sortkey, temp_contact->sortkey);
1284                 FREEandSTRDUP(contact->reverse_sortkey, temp_contact->reverse_sortkey);
1285
1286                 contact->display_name_language = temp_contact->display_name_language;
1287                 contact->reverse_display_name_language = temp_contact->reverse_display_name_language;
1288                 contact->display_source_type = temp_contact->display_source_type;
1289
1290                 if (ctsvc_record_check_property_flag((ctsvc_record_s*)temp_contact, _contacts_contact.display_name, CTSVC_PROPERTY_FLAG_DIRTY))
1291                         ctsvc_record_set_property_flag((ctsvc_record_s*)contact, _contacts_contact.display_name, CTSVC_PROPERTY_FLAG_DIRTY);
1292
1293                 contacts_record_destroy((contacts_record_h)temp_contact, true);
1294         } else {
1295                 ctsvc_contact_make_display_name(contact);
1296         }
1297
1298         do {
1299                 char query[CTS_SQL_MAX_LEN] = {0};
1300                 char query_set[CTS_SQL_MIN_LEN] = {0, };
1301                 cts_stmt stmt = NULL;
1302
1303                 version = ctsvc_get_next_ver();
1304
1305                 ret = ctsvc_db_create_set_query(record, &set, &bind_text);
1306                 WARN_IF(CONTACTS_ERROR_NONE != ret, "ctsvc_db_create_set_query() Fail(%d)", ret);
1307
1308                 if (set && *set)
1309                         len = snprintf(query_set, sizeof(query_set), "%s, ", set);
1310                 len += snprintf(query_set+len, sizeof(query_set)-len, " changed_ver=%d, changed_time=%d, has_phonenumber=%d, has_email=%d",
1311                                 version, (int)time(NULL), contact->has_phonenumber, contact->has_email);
1312                 if (ctsvc_record_check_property_flag((ctsvc_record_s*)contact, _contacts_contact.display_name, CTSVC_PROPERTY_FLAG_DIRTY)) {
1313                         len += snprintf(query_set+len, sizeof(query_set)-len,
1314                                         ", display_name=?, reverse_display_name=?, display_name_source=%d, "
1315                                         "display_name_language=%d, reverse_display_name_language=%d, "
1316                                         "sort_name=?, reverse_sort_name=?, sortkey=?, reverse_sortkey=?",
1317                                         contact->display_source_type, contact->display_name_language, contact->reverse_display_name_language);
1318                         bind_text = g_slist_append(bind_text, strdup(SAFE_STR(contact->display_name)));
1319                         bind_text = g_slist_append(bind_text, strdup(SAFE_STR(contact->reverse_display_name)));
1320                         bind_text = g_slist_append(bind_text, strdup(SAFE_STR(contact->sort_name)));
1321                         bind_text = g_slist_append(bind_text, strdup(SAFE_STR(contact->reverse_sort_name)));
1322                         bind_text = g_slist_append(bind_text, strdup(SAFE_STR(contact->sortkey)));
1323                         bind_text = g_slist_append(bind_text, strdup(SAFE_STR(contact->reverse_sortkey)));
1324                 }
1325
1326                 if (ctsvc_record_check_property_flag((ctsvc_record_s*)contact, _contacts_contact.image_thumbnail_path, CTSVC_PROPERTY_FLAG_DIRTY))
1327                         len += snprintf(query_set+len, sizeof(query_set)-len, ", image_changed_ver=%d", version);
1328
1329                 snprintf(query, sizeof(query), "UPDATE %s SET %s WHERE contact_id = %d", CTS_TABLE_CONTACTS, query_set, contact->id);
1330
1331                 ret = ctsvc_query_prepare(query, &stmt);
1332                 if (NULL == stmt) {
1333                         ERR("ctsvc_query_prepare() Fail(%d)", ret);
1334                         break;
1335                 }
1336
1337                 if (bind_text) {
1338                         int i = 0;
1339                         for (cursor = bind_text, i = 1; cursor; cursor = cursor->next, i++) {
1340                                 const char *text = cursor->data;
1341                                 if (*text)
1342                                         ctsvc_stmt_bind_text(stmt, i, text);
1343                         }
1344                 }
1345                 ret = ctsvc_stmt_step(stmt);
1346                 if (CONTACTS_ERROR_NONE != ret) {
1347                         ERR("ctsvc_stmt_step() Fail(%d)", ret);
1348                         ctsvc_stmt_finalize(stmt);
1349                         break;
1350                 }
1351                 ctsvc_stmt_finalize(stmt);
1352         } while (0);
1353
1354         if (CONTACTS_ERROR_NONE != ret) {
1355                 ctsvc_end_trans(false);
1356                 CTSVC_RECORD_RESET_PROPERTY_FLAGS((ctsvc_record_s*)record);
1357                 free(set);
1358
1359                 if (bind_text) {
1360                         for (cursor = bind_text; cursor; cursor = cursor->next) {
1361                                 free(cursor->data);
1362                                 cursor->data = NULL;
1363                         }
1364                         g_slist_free(bind_text);
1365                 }
1366                 return ret;
1367         }
1368
1369         ctsvc_set_contact_noti();
1370         if (0 < rel_changed)
1371                 ctsvc_set_group_rel_noti();
1372
1373         __ctsvc_contact_update_search_data(contact->id, need_update_lookup);
1374         ctsvc_db_update_person((contacts_record_h)contact);
1375
1376         CTSVC_RECORD_RESET_PROPERTY_FLAGS((ctsvc_record_s*)record);
1377         free(set);
1378
1379         if (bind_text) {
1380                 for (cursor = bind_text; cursor; cursor = cursor->next) {
1381                         free(cursor->data);
1382                         cursor->data = NULL;
1383                 }
1384                 g_slist_free(bind_text);
1385         }
1386
1387         ret = ctsvc_end_trans(true);
1388         RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_end_trans() Fail(%d)", ret);
1389
1390         return CONTACTS_ERROR_NONE;
1391 }
1392
1393 static int __ctsvc_db_contact_get_all_records(int offset, int limit, contacts_list_h *out_list)
1394 {
1395         int ret;
1396         int len;
1397         int contact_id;
1398         cts_stmt stmt;
1399         char query[CTS_SQL_MAX_LEN] = {0};
1400         contacts_list_h list;
1401
1402         len = snprintf(query, sizeof(query),
1403                         "SELECT contact_id FROM "CTS_TABLE_CONTACTS" WHERE deleted = 0");
1404
1405         if (0 != limit) {
1406                 len += snprintf(query+len, sizeof(query)-len, " LIMIT %d", limit);
1407                 if (0 < offset)
1408                         len += snprintf(query+len, sizeof(query)-len, " OFFSET %d", offset);
1409         }
1410
1411         ret = ctsvc_query_prepare(query, &stmt);
1412         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1413
1414         contacts_list_create(&list);
1415         while ((ret = ctsvc_stmt_step(stmt))) {
1416                 contacts_record_h record;
1417                 if (1 != ret) {
1418                         ERR("ctsvc_stmt_step() Fail(%d)", ret);
1419                         ctsvc_stmt_finalize(stmt);
1420                         contacts_list_destroy(list, true);
1421                         return ret;
1422                 }
1423                 contact_id = ctsvc_stmt_get_int(stmt, 0);
1424                 ret = ctsvc_db_contact_get(contact_id, &record);
1425                 if (CONTACTS_ERROR_NONE != ret) {
1426                         ERR("ctsvc_db_contact_get() Fail(%d)", ret);
1427                         ctsvc_stmt_finalize(stmt);
1428                         contacts_list_destroy(list, true);
1429                         return ret;
1430                 }
1431                 ctsvc_list_prepend(list, record);
1432         }
1433         ctsvc_stmt_finalize(stmt);
1434         ctsvc_list_reverse(list);
1435
1436         *out_list = (contacts_list_h)list;
1437         return CONTACTS_ERROR_NONE;
1438 }
1439
1440 static int __ctsvc_db_contact_get_changed_ver(int contact_id, ctsvc_contact_s *contact)
1441 {
1442         int ret;
1443         int version;
1444         char query[CTS_SQL_MAX_LEN] = {0};
1445
1446         snprintf(query, sizeof(query),
1447                         "SELECT changed_ver FROM "CTS_TABLE_CONTACTS
1448                         " WHERE contact_id = %d AND deleted = 0", contact_id);
1449         ret = ctsvc_query_get_first_int_result(query, &version);
1450         if (CONTACTS_ERROR_NONE == ret)
1451                 contact->changed_ver = version;
1452         return ret;
1453 }
1454
1455 static int __ctsvc_db_contact_get_records_with_query(contacts_query_h query, int offset, int limit, contacts_list_h *out_list)
1456 {
1457         int ret;
1458         int i;
1459         int field_count;
1460         ctsvc_query_s *s_query;
1461         cts_stmt stmt;
1462         contacts_list_h list;
1463         ctsvc_contact_s *contact;
1464         char full_path[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
1465         bool had_contact_id = false;
1466         int contact_id = 0;
1467
1468         RETV_IF(NULL == query, CONTACTS_ERROR_INVALID_PARAMETER);
1469         s_query = (ctsvc_query_s*)query;
1470
1471         if (s_query->projection) {
1472                 for (i = 0; i < s_query->projection_count; i++) {
1473                         if (s_query->projection[i] == CTSVC_PROPERTY_CONTACT_ID) {
1474                                 had_contact_id = true;
1475                                 break;
1476                         }
1477                 }
1478         } else {
1479                 s_query->projection_count = 0;
1480                 had_contact_id = true;
1481         }
1482
1483         if (false == had_contact_id) {
1484                 s_query->projection = realloc(s_query->projection, s_query->projection_count+1);
1485                 if (NULL == s_query->projection) {
1486                         ERR("realloc() Fail");
1487                         return CONTACTS_ERROR_OUT_OF_MEMORY;
1488                 }
1489
1490                 s_query->projection[s_query->projection_count] = CTSVC_PROPERTY_CONTACT_ID;
1491                 s_query->projection_count++;
1492         }
1493
1494         ret = ctsvc_db_make_get_records_query_stmt(s_query, offset, limit, &stmt);
1495         RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_db_make_get_records_query_stmt fail(%d)", ret);
1496
1497         contacts_list_create(&list);
1498         while ((ret = ctsvc_stmt_step(stmt))) {
1499                 contacts_record_h record;
1500                 if (1 != ret) {
1501                         ERR("ctsvc_stmt_step() Fail(%d)", ret);
1502                         ctsvc_stmt_finalize(stmt);
1503                         contacts_list_destroy(list, true);
1504                         return ret;
1505                 }
1506
1507                 contacts_record_create(_contacts_contact._uri, &record);
1508                 contact = (ctsvc_contact_s*)record;
1509                 if (0 == s_query->projection_count) {
1510                         field_count = s_query->property_count;
1511                 } else {
1512                         field_count = s_query->projection_count;
1513                         ret = ctsvc_record_set_projection_flags(record, s_query->projection,
1514                                         s_query->projection_count, s_query->property_count);
1515
1516                         if (CONTACTS_ERROR_NONE != ret)
1517                                 ASSERT_NOT_REACHED("To set projection is failed.\n");
1518                 }
1519
1520                 for (i = 0; i < field_count; i++) {
1521                         char *temp;
1522                         int property_id;
1523                         if (0 == s_query->projection_count)
1524                                 property_id = s_query->properties[i].property_id;
1525                         else
1526                                 property_id = s_query->projection[i];
1527
1528                         switch (property_id) {
1529                         case CTSVC_PROPERTY_CONTACT_ID:
1530                                 contact_id = ctsvc_stmt_get_int(stmt, i);
1531                                 if (had_contact_id)
1532                                         contact->id = contact_id;
1533                                 break;
1534                         case CTSVC_PROPERTY_CONTACT_DISPLAY_NAME:
1535                                 temp = ctsvc_stmt_get_text(stmt, i);
1536                                 free(contact->display_name);
1537                                 contact->display_name = SAFE_STRDUP(temp);
1538                                 break;
1539                         case CTSVC_PROPERTY_CONTACT_DISPLAY_SOURCE_DATA_ID:
1540                                 contact->display_source_type = ctsvc_stmt_get_int(stmt, i);
1541                                 break;
1542                         case CTSVC_PROPERTY_CONTACT_ADDRESSBOOK_ID:
1543                                 contact->addressbook_id = ctsvc_stmt_get_int(stmt, i);
1544                                 break;
1545                         case CTSVC_PROPERTY_CONTACT_RINGTONE:
1546                                 temp = ctsvc_stmt_get_text(stmt, i);
1547                                 free(contact->ringtone_path);
1548                                 contact->ringtone_path = SAFE_STRDUP(temp);
1549                                 break;
1550                         case CTSVC_PROPERTY_CONTACT_IMAGE_THUMBNAIL:
1551                                 temp = ctsvc_stmt_get_text(stmt, i);
1552                                 if (temp && *temp) {
1553                                         snprintf(full_path, sizeof(full_path), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, temp);
1554                                         free(contact->image_thumbnail_path);
1555                                         contact->image_thumbnail_path = strdup(full_path);
1556                                 }
1557                                 break;
1558                         case CTSVC_PROPERTY_CONTACT_IS_FAVORITE:
1559                                 contact->is_favorite = ctsvc_stmt_get_int(stmt, i);
1560                                 break;
1561                         case CTSVC_PROPERTY_CONTACT_HAS_PHONENUMBER:
1562                                 contact->has_phonenumber = ctsvc_stmt_get_int(stmt, i);
1563                                 break;
1564                         case CTSVC_PROPERTY_CONTACT_HAS_EMAIL:
1565                                 contact->has_email = ctsvc_stmt_get_int(stmt, i);
1566                                 break;
1567                         case CTSVC_PROPERTY_CONTACT_PERSON_ID:
1568                                 contact->person_id = ctsvc_stmt_get_int(stmt, i);
1569                                 break;
1570                         case CTSVC_PROPERTY_CONTACT_UID:
1571                                 temp = ctsvc_stmt_get_text(stmt, i);
1572                                 free(contact->uid);
1573                                 contact->uid = SAFE_STRDUP(temp);
1574                                 break;
1575                         case CTSVC_PROPERTY_CONTACT_VIBRATION:
1576                                 temp = ctsvc_stmt_get_text(stmt, i);
1577                                 free(contact->vibration);
1578                                 contact->vibration = SAFE_STRDUP(temp);
1579                                 break;
1580                         case CTSVC_PROPERTY_CONTACT_MESSAGE_ALERT:
1581                                 temp = ctsvc_stmt_get_text(stmt, i);
1582                                 free(contact->message_alert);
1583                                 contact->message_alert = SAFE_STRDUP(temp);
1584                                 break;
1585                         case CTSVC_PROPERTY_CONTACT_CHANGED_TIME:
1586                                 contact->changed_time = ctsvc_stmt_get_int(stmt, i);
1587                                 break;
1588                         case CTSVC_PROPERTY_CONTACT_LINK_MODE:
1589                                 contact->link_mode = ctsvc_stmt_get_int(stmt, i);
1590                                 break;
1591                         default:
1592                                 break;
1593                         }
1594                 }
1595                 /* get changed_ver */
1596                 ret = __ctsvc_db_contact_get_changed_ver(contact_id, contact);
1597                 if (CONTACTS_ERROR_NONE != ret) {
1598                         ERR("__ctsvc_db_contact_get_changed_ver Fail(%d)", ret);
1599                         ctsvc_stmt_finalize(stmt);
1600                         contacts_list_destroy(list, true);
1601                         return ret;
1602                 }
1603
1604                 ret = __ctsvc_db_get_data(contact_id, contact);
1605                 if (CONTACTS_ERROR_NONE != ret && CONTACTS_ERROR_NO_DATA != ret) {
1606                         ERR("ctsvc_get_data_info Fail(%d)", ret);
1607                         ctsvc_stmt_finalize(stmt);
1608                         contacts_list_destroy(list, true);
1609                         return ret;
1610                 }
1611
1612                 ret = __ctsvc_get_contact_grouprel(contact_id, contact);
1613                 if (CONTACTS_ERROR_NONE != ret) {
1614                         ERR("ctsvc_get_group_relations Fail(%d)", ret);
1615                         ctsvc_stmt_finalize(stmt);
1616                         contacts_list_destroy(list, true);
1617                         return ret;
1618                 }
1619
1620                 ctsvc_list_prepend(list, record);
1621         }
1622         ctsvc_stmt_finalize(stmt);
1623         ctsvc_list_reverse(list);
1624
1625         *out_list = (contacts_list_h)list;
1626
1627         return CONTACTS_ERROR_NONE;
1628 }
1629
1630
1631 static int __ctsvc_contact_insert_data(ctsvc_contact_s *contact)
1632 {
1633         int ret;
1634
1635         /* Insert the name */
1636         if (contact->name) {
1637                 ret = ctsvc_contact_insert_data_name((contacts_list_h)contact->name, contact->id, false);
1638                 if (CONTACTS_ERROR_NONE != ret) {
1639                         ERR("ctsvc_contact_insert_data_name() Fail(%d)", ret);
1640                         return ret;
1641                 }
1642         }
1643
1644         /* Insert the company */
1645         if (contact->company) {
1646                 ret = ctsvc_contact_insert_data_company((contacts_list_h)contact->company, contact->id, false);
1647                 if (CONTACTS_ERROR_NONE != ret) {
1648                         ERR("ctsvc_insert_contact_data_company() Fail(%d)", ret);
1649                         return ret;
1650                 }
1651         }
1652
1653         /* Insert the events */
1654         if (contact->events) {
1655                 ret = ctsvc_contact_insert_data_event((contacts_list_h)contact->events, contact->id, false);
1656                 if (CONTACTS_ERROR_NONE != ret) {
1657                         ERR("ctsvc_insert_contact_data_event() Fail(%d)", ret);
1658                         return ret;
1659                 }
1660         }
1661
1662         /* Insert the messengers */
1663         if (contact->messengers) {
1664                 ret = ctsvc_contact_insert_data_messenger((contacts_list_h)contact->messengers, contact->id, false);
1665                 if (CONTACTS_ERROR_NONE != ret) {
1666                         ERR("ctsvc_insert_contact_data_messenger() Fail(%d)", ret);
1667                         return ret;
1668                 }
1669         }
1670
1671         /* Insert the postals */
1672         if (contact->postal_addrs) {
1673                 ret = ctsvc_contact_insert_data_address((contacts_list_h)contact->postal_addrs, contact->id, false);
1674                 if (CONTACTS_ERROR_NONE != ret) {
1675                         ERR("ctsvc_insert_contact_data_postal() Fail(%d)", ret);
1676                         return ret;
1677                 }
1678         }
1679
1680         /* Insert the Web addrs */
1681         if (contact->urls) {
1682                 ret = ctsvc_contact_insert_data_url((contacts_list_h)contact->urls, contact->id, false);
1683                 if (CONTACTS_ERROR_NONE != ret) {
1684                         ERR("ctsvc_insert_contact_data_web() Fail(%d)", ret);
1685                         return ret;
1686                 }
1687         }
1688
1689         /* Insert the Nick names */
1690         if (contact->nicknames) {
1691                 ret = ctsvc_contact_insert_data_nickname((contacts_list_h)contact->nicknames, contact->id, false);
1692                 if (CONTACTS_ERROR_NONE != ret) {
1693                         ERR("ctsvc_insert_contact_data_nickname() Fail(%d)", ret);
1694                         return ret;
1695                 }
1696         }
1697
1698         /* Insert the numbers */
1699         if (contact->numbers) {
1700                 ret = ctsvc_contact_insert_data_number((contacts_list_h)contact->numbers, contact->id, false);
1701                 if (ret < CONTACTS_ERROR_NONE) {
1702                         ERR("ctsvc_contact_insert_data_number() Fail(%d)", ret);
1703                         return ret;
1704                 }
1705         }
1706
1707         /* Insert the emails */
1708         if (contact->emails) {
1709                 ret = ctsvc_contact_insert_data_email((contacts_list_h)contact->emails, contact->id, false);
1710                 if (ret < CONTACTS_ERROR_NONE) {
1711                         ERR("ctsvc_insert_contact_data_email() Fail(%d)", ret);
1712                         return ret;
1713                 }
1714         }
1715
1716         /* Insert the profile values */
1717         if (contact->profiles) {
1718                 ret = ctsvc_contact_insert_data_profile((contacts_list_h)contact->profiles, contact->id, false);
1719                 if (CONTACTS_ERROR_NONE != ret) {
1720                         ERR("ctsvc_insert_contact_data_profile() Fail(%d)", ret);
1721                         return ret;
1722                 }
1723         }
1724
1725         /* Insert the relationship values */
1726         if (contact->relationships) {
1727                 ret = ctsvc_contact_insert_data_relationship((contacts_list_h)contact->relationships, contact->id, false);
1728                 if (CONTACTS_ERROR_NONE != ret) {
1729                         ERR("ctsvc_contact_insert_data_relationship() Fail(%d)", ret);
1730                         return ret;
1731                 }
1732         }
1733
1734         /* Insert the image values */
1735         if (contact->images) {
1736                 ret = ctsvc_contact_insert_data_image((contacts_list_h)contact->images, contact->id, false);
1737                 if (CONTACTS_ERROR_NONE != ret) {
1738                         ERR("ctsvc_contact_insert_data_image() Fail(%d)", ret);
1739                         return ret;
1740                 }
1741         }
1742
1743         /* Insert the note values */
1744         if (contact->note) {
1745                 ret = ctsvc_contact_insert_data_note((contacts_list_h)contact->note, contact->id, false);
1746                 if (CONTACTS_ERROR_NONE != ret) {
1747                         ERR("ctsvc_contact_insert_data_note() Fail(%d)", ret);
1748                         return ret;
1749                 }
1750         }
1751
1752         /* Insert the extensions values */
1753         if (contact->extensions) {
1754                 ret = ctsvc_contact_insert_data_extension((contacts_list_h)contact->extensions, contact->id, false);
1755                 if (CONTACTS_ERROR_NONE != ret) {
1756                         ERR("ctsvc_contact_insert_data_extension() Fail(%d)", ret);
1757                         return ret;
1758                 }
1759         }
1760
1761         /* Insert the sips */
1762         if (contact->sips) {
1763                 ret = ctsvc_contact_insert_data_sip((contacts_list_h)contact->sips, contact->id, false);
1764                 if (CONTACTS_ERROR_NONE != ret) {
1765                         ERR("ctsvc_insert_contact_data_sip() Fail(%d)", ret);
1766                         return ret;
1767                 }
1768         }
1769
1770         return CONTACTS_ERROR_NONE;
1771 }
1772
1773 static inline int __ctsvc_contact_insert_search_data(int contact_id, bool need_insert_lookup_data)
1774 {
1775         int ret;
1776         cts_stmt stmt = NULL;
1777         char query[CTS_SQL_MAX_LEN] = {0};
1778         char *search_name = NULL;
1779         char *search_number = NULL;
1780         char *search_data = NULL;
1781         ctsvc_contact_s *contact = NULL;
1782
1783         ret = ctsvc_begin_trans();
1784         RETVM_IF(ret, ret, "contacts_begin_trans() Fail(%d)", ret);
1785
1786         ret = ctsvc_db_contact_get(contact_id, (contacts_record_h*)&contact);
1787         if (CONTACTS_ERROR_NONE != ret) {
1788                 ERR("ctsvc_db_contact_get() Fail(%d)", ret);
1789                 ctsvc_end_trans(false);
1790                 return ret;
1791         }
1792
1793         ret = ctsvc_contact_make_search_name(contact, &search_name);
1794         if (CONTACTS_ERROR_NONE != ret) {
1795                 ERR("ctsvc_contact_make_search_name() Fail(%d)", ret);
1796                 contacts_record_destroy((contacts_record_h)contact, true);
1797                 ctsvc_end_trans(false);
1798                 return ret;
1799         }
1800
1801         ret = __ctsvc_contact_make_search_data(contact, &search_number, &search_data);
1802         if (CONTACTS_ERROR_NONE != ret) {
1803                 ERR("__ctsvc_contact_make_search_data() Fail(%d)", ret);
1804                 contacts_record_destroy((contacts_record_h)contact, true);
1805                 ctsvc_end_trans(false);
1806                 free(search_name);
1807                 return ret;
1808         }
1809
1810         snprintf(query, sizeof(query),
1811                         "INSERT INTO %s(contact_id, name, number, data) "
1812                         "VALUES(%d, ?, ?, ?)",
1813                         CTS_TABLE_SEARCH_INDEX, contact_id);
1814
1815         ret = ctsvc_query_prepare(query, &stmt);
1816         if (NULL == stmt) {
1817                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
1818                 contacts_record_destroy((contacts_record_h)contact, true);
1819                 ctsvc_end_trans(false);
1820                 free(search_name);
1821                 free(search_number);
1822                 free(search_data);
1823                 return ret;
1824         }
1825
1826         if (search_name)
1827                 ctsvc_stmt_bind_text(stmt, 1, search_name);
1828         if (search_number)
1829                 ctsvc_stmt_bind_text(stmt, 2, search_number);
1830         if (search_data)
1831                 ctsvc_stmt_bind_text(stmt, 3, search_data);
1832
1833         ret = ctsvc_stmt_step(stmt);
1834
1835         free(search_name);
1836         free(search_number);
1837         free(search_data);
1838
1839         if (CONTACTS_ERROR_NONE != ret) {
1840                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
1841                 contacts_record_destroy((contacts_record_h)contact, true);
1842                 ctsvc_stmt_finalize(stmt);
1843                 ctsvc_end_trans(false);
1844                 return ret;
1845         }
1846         ctsvc_stmt_finalize(stmt);
1847
1848         /* update phone_lookup, name_lookup */
1849         if (need_insert_lookup_data) {
1850                 ret = __ctsvc_contact_refresh_lookup_data(contact_id, contact);
1851                 if (CONTACTS_ERROR_NONE != ret) {
1852                         ERR("__ctsvc_contact_refresh_lookup_data() Fail(%d)", ret);
1853                         contacts_record_destroy((contacts_record_h)contact, true);
1854                         ctsvc_end_trans(false);
1855                         return ret;
1856                 }
1857         }
1858
1859         contacts_record_destroy((contacts_record_h)contact, true);
1860
1861         ret = ctsvc_end_trans(true);
1862         RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_end_trans() Fail(%d)", ret);
1863
1864         return CONTACTS_ERROR_NONE;
1865 }
1866
1867 static inline int __ctsvc_contact_insert_grouprel(int contact_id, contacts_list_h group_list)
1868 {
1869         CTS_FN_CALL;
1870         ctsvc_group_relation_s *grouprel;
1871         int rel_changed = 0;
1872         int count;
1873         int ret;
1874
1875         RETV_IF(NULL == group_list, CONTACTS_ERROR_INVALID_PARAMETER);
1876         ret = contacts_list_get_count(group_list, &count);
1877         if (0 == count)
1878                 return CONTACTS_ERROR_NONE;
1879
1880         contacts_list_first(group_list);
1881         do {
1882                 contacts_list_get_current_record_p(group_list, (contacts_record_h*)&grouprel);
1883                 if (NULL == grouprel)
1884                         continue;
1885
1886                 RETVM_IF(grouprel->group_id <= 0, CONTACTS_ERROR_INVALID_PARAMETER, "group_id(%d) invalid", grouprel->group_id);
1887                 if (grouprel->group_id) {
1888                         ret = ctsvc_group_add_contact_in_transaction(grouprel->group_id, contact_id);
1889                         RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_db_group_set_relation() Fail(%d)", ret);
1890                         if (0 < ret)
1891                                 rel_changed += ret;
1892                 }
1893         } while (CONTACTS_ERROR_NONE == contacts_list_next(group_list));
1894
1895         if (rel_changed)
1896                 return rel_changed;
1897         else
1898                 return CONTACTS_ERROR_NONE;
1899 }
1900
1901 static inline int __ctsvc_find_person_to_link_with_number(const char *number,
1902                 int addressbook_id, int *person_id)
1903 {
1904         int ret;
1905         cts_stmt stmt = NULL;
1906         char query[CTS_SQL_MIN_LEN] = {0};
1907         int number_len = SAFE_STRLEN(number);
1908         char clean_num[number_len+1];
1909
1910         ret = ctsvc_clean_number(number, clean_num, sizeof(clean_num), true);
1911         if (0 < ret) {
1912                 char normal_num[sizeof(clean_num)+20];
1913                 ret = ctsvc_normalize_number(clean_num, normal_num, sizeof(normal_num), true);
1914                 char minmatch[sizeof(normal_num)+1];
1915                 if (0 < ret)
1916                         ret = ctsvc_get_minmatch_number(normal_num, minmatch, sizeof(minmatch), ctsvc_get_phonenumber_min_match_digit());
1917
1918                 snprintf(query, sizeof(query),
1919                                 "SELECT C.person_id FROM "CTS_TABLE_CONTACTS" C, "CTS_TABLE_DATA" D "
1920                                 "ON C.contact_id=D.contact_id AND D.datatype=%d AND C.deleted = 0 "
1921                                 "AND C.addressbook_id <> %d AND D.is_my_profile = 0 "
1922                                 "WHERE D.data4 = ?",
1923                                 /* Below condition takes long time, so omit the condition */
1924                                 /* AND _NUMBER_COMPARE_(D.data5, ?, NULL, NULL) */
1925                                 CTSVC_DATA_NUMBER, addressbook_id);
1926
1927                 ret = ctsvc_query_prepare(query, &stmt);
1928                 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare fail(%d)", ret);
1929                 ctsvc_stmt_bind_text(stmt, 1, minmatch);
1930                 /* ctsvc_stmt_bind_text(stmt, 2, normal_num); */
1931                 ret = ctsvc_stmt_step(stmt);
1932                 if (1 == ret) {
1933                         *person_id = ctsvc_stmt_get_int(stmt, 0);
1934                         ret = CONTACTS_ERROR_NONE;
1935                 } else if (CONTACTS_ERROR_NONE == ret) {
1936                         ret = CONTACTS_ERROR_NO_DATA;
1937                 }
1938                 ctsvc_stmt_finalize(stmt);
1939                 DBG("result ret(%d) person_id(%d)", ret, *person_id);
1940                 return ret;
1941         }
1942
1943         return CONTACTS_ERROR_INVALID_PARAMETER;
1944 }
1945
1946 static inline int __ctsvc_find_person_to_link_with_email(const char *email_addr, int addressbook_id, int *person_id)
1947 {
1948         int ret;
1949         cts_stmt stmt = NULL;
1950         char query[CTS_SQL_MIN_LEN] = {0};
1951
1952         snprintf(query, sizeof(query),
1953                         "SELECT C.person_id FROM "CTS_TABLE_CONTACTS" C, "CTS_TABLE_DATA" D "
1954                         "ON C.contact_id=D.contact_id AND D.datatype=%d AND C.deleted = 0 AND D.is_my_profile = 0 "
1955                         "AND C.addressbook_id <> %d "
1956                         "WHERE D.data3 = ?",
1957                         CTSVC_DATA_EMAIL, addressbook_id);
1958
1959         ret = ctsvc_query_prepare(query, &stmt);
1960         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare fail(%d)", ret);
1961
1962         ctsvc_stmt_bind_text(stmt, 1, email_addr);
1963         ret = ctsvc_stmt_step(stmt);
1964         if (1 == ret) {
1965                 *person_id = ctsvc_stmt_get_int(stmt, 0);
1966                 ret = CONTACTS_ERROR_NONE;
1967         } else if (CONTACTS_ERROR_NONE == ret) {
1968                 ret = CONTACTS_ERROR_NO_DATA;
1969         }
1970
1971         ctsvc_stmt_finalize(stmt);
1972         DBG("result ret(%d) person_id(%d)", ret, *person_id);
1973
1974         return ret;
1975 }
1976
1977 static inline int __ctsvc_find_person_to_link(contacts_record_h record, int addressbook_id, int *person_id)
1978 {
1979         int ret;
1980         ctsvc_contact_s *contact = (ctsvc_contact_s*)record;
1981         ctsvc_number_s *number_data;
1982         ctsvc_email_s *email_data;
1983         GList *cursor;
1984
1985         for (cursor = contact->numbers->records; cursor; cursor = cursor->next) {
1986                 number_data = cursor->data;
1987                 if (number_data && number_data->number && number_data->number[0]) {
1988                         ret = __ctsvc_find_person_to_link_with_number(number_data->number, addressbook_id, person_id);
1989
1990                         if (ret == CONTACTS_ERROR_NONE && 0 < *person_id)
1991                                 return ret;
1992                 }
1993         }
1994
1995         for (cursor = contact->emails->records; cursor; cursor = cursor->next) {
1996                 email_data = cursor->data;
1997                 if (email_data && email_data->email_addr && email_data->email_addr[0]) {
1998                         ret = __ctsvc_find_person_to_link_with_email(email_data->email_addr, addressbook_id, person_id);
1999
2000                         if (ret == CONTACTS_ERROR_NONE && 0 < *person_id)
2001                                 return ret;
2002                 }
2003         }
2004
2005         return CONTACTS_ERROR_NO_DATA;
2006 }
2007
2008 static int __ctsvc_db_contact_insert_record(contacts_record_h record, int *id)
2009 {
2010         int version;
2011         int ret, person_id = 0;
2012         char query[CTS_SQL_MAX_LEN] = {0};
2013         bool auto_link_enabled = true;
2014         bool auto_linked = false;
2015
2016         ctsvc_contact_s *contact = (ctsvc_contact_s*)record;
2017         int rel_changed = 0;
2018         cts_stmt stmt = NULL;
2019
2020         /* These check should be done in client side */
2021         RETV_IF(NULL == contact, CONTACTS_ERROR_INVALID_PARAMETER);
2022         RETVM_IF(contact->addressbook_id < 0, CONTACTS_ERROR_INVALID_PARAMETER,
2023                         "addressbook_id(%d) is mandatory field to insert contact record ", contact->addressbook_id);
2024         RETVM_IF(0 < contact->id, CONTACTS_ERROR_INVALID_PARAMETER,
2025                         "id(%d), This record is already inserted", contact->id);
2026
2027         if (contact->link_mode == CONTACTS_CONTACT_LINK_MODE_IGNORE_ONCE)
2028                 auto_link_enabled = false;
2029
2030         ret = ctsvc_begin_trans();
2031         RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_begin_trans() Fail(%d)", ret);
2032
2033         if (false == ctsvc_have_ab_write_permission(contact->addressbook_id, false)) {
2034                 ERR("No permission in this addresbook_id(%d)", contact->addressbook_id);
2035                 ctsvc_end_trans(false);
2036                 return CONTACTS_ERROR_PERMISSION_DENIED;
2037         }
2038
2039         ret = ctsvc_db_get_next_id(CTS_TABLE_CONTACTS);
2040         if (ret < CONTACTS_ERROR_NONE) {
2041                 ERR("ctsvc_db_get_next_id() Fail(%d)", ret);
2042                 ctsvc_end_trans(false);
2043                 return ret;
2044         }
2045         contact->id = ret;
2046         if (id)
2047                 *id = ret;
2048
2049         ctsvc_contact_make_display_name(contact);
2050         __ctsvc_contact_check_default_data(contact);
2051
2052         /* check lookup data is dirty */
2053         bool need_insert_lookup = __ctsvc_get_need_refresh_lookup_data(contact);
2054
2055         /* Insert Data */
2056         ret = __ctsvc_contact_insert_data(contact);
2057         if (CONTACTS_ERROR_NONE != ret) {
2058                 ERR("cts_insert_contact_data() Fail(%d)", ret);
2059                 ctsvc_end_trans(false);
2060                 return ret;
2061         }
2062
2063         /* thumbnail */
2064         free(contact->image_thumbnail_path);
2065         contact->image_thumbnail_path = NULL;
2066         if (contact->images) {
2067                 int count = 0;
2068                 ctsvc_image_s *image;
2069
2070                 contacts_list_get_count((contacts_list_h)contact->images, &count);
2071                 if (count) {
2072                         contacts_list_first((contacts_list_h)contact->images);
2073                         do {
2074                                 ret = contacts_list_get_current_record_p((contacts_list_h)contact->images, (contacts_record_h*)&image);
2075                                 if (CONTACTS_ERROR_NONE != ret) {
2076                                         ERR("contacts_list_get_current_record_p() Fail(%d)", ret);
2077                                         ctsvc_end_trans(false);
2078                                         return CONTACTS_ERROR_DB;
2079                                 }
2080
2081                                 if (image->path && image->is_default) {
2082                                         contact->image_thumbnail_path = strdup(image->path);
2083                                         break;
2084                                 }
2085                         } while (CONTACTS_ERROR_NONE == contacts_list_next((contacts_list_h)contact->images));
2086                 }
2087         }
2088
2089         version = ctsvc_get_next_ver();
2090
2091         if (contact->person_id) {
2092                 int id;
2093
2094                 snprintf(query, sizeof(query),
2095                                 "SELECT contact_id FROM "CTSVC_DB_VIEW_CONTACT" "
2096                                 "WHERE person_id = %d", contact->person_id);
2097                 ret = ctsvc_query_get_first_int_result(query, &id);
2098                 if (CONTACTS_ERROR_NONE != ret) {
2099                         ERR("Invalid person_id(%d)", contact->person_id);
2100                         ctsvc_end_trans(false);
2101                         return CONTACTS_ERROR_INVALID_PARAMETER;
2102                 }
2103
2104                 auto_linked = true;
2105         } else if (auto_link_enabled) {
2106                 ret = __ctsvc_find_person_to_link((contacts_record_h)contact, contact->addressbook_id, &person_id);
2107                 DBG("__ctsvc_find_person_to_link return %d, person_id(%d)", ret, person_id);
2108                 if (ret == CONTACTS_ERROR_NONE && 0 < person_id) {
2109                         contact->person_id = person_id;
2110                         auto_linked = true;
2111                 } else {
2112                         ret = ctsvc_db_insert_person((contacts_record_h)contact);
2113                         DBG("ctsvc_db_insert_person return %d, person_id(%d)", ret, ret);
2114                         if (ret < CONTACTS_ERROR_NONE) {
2115                                 ERR("ctsvc_db_insert_person() Fail(%d)", ret);
2116                                 ctsvc_end_trans(false);
2117                                 return ret;
2118                         }
2119                         contact->person_id = ret;
2120                 }
2121         } else {
2122                 ret = ctsvc_db_insert_person((contacts_record_h)contact);
2123                 DBG("ctsvc_db_insert_person return %d, person_id(%d)", ret, ret);
2124                 if (ret < CONTACTS_ERROR_NONE) {
2125                         ERR("ctsvc_db_insert_person() Fail(%d)", ret);
2126                         ctsvc_end_trans(false);
2127                         return ret;
2128                 }
2129                 contact->person_id = ret;
2130         }
2131
2132         snprintf(query, sizeof(query),
2133                         "INSERT INTO "CTS_TABLE_CONTACTS"(contact_id, person_id, addressbook_id, is_favorite, "
2134                         "created_ver, changed_ver, changed_time, link_mode, "
2135                         "image_changed_ver, has_phonenumber, has_email, "
2136                         "display_name, reverse_display_name, display_name_source, "
2137                         "display_name_language, reverse_display_name_language, "
2138                         "sort_name, reverse_sort_name, "
2139                         "sortkey, reverse_sortkey, "
2140                         "uid, ringtone_path, vibration, message_alert, image_thumbnail_path) "
2141                         "VALUES(%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, ?, ?, %d, %d, %d, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
2142                         contact->id, contact->person_id, contact->addressbook_id, contact->is_favorite,
2143                         version, version, (int)time(NULL), contact->link_mode,
2144                         (contact->image_thumbnail_path) ? version : 0, contact->has_phonenumber, contact->has_email,
2145                         contact->display_source_type, contact->display_name_language, contact->reverse_display_name_language);
2146
2147         ret = ctsvc_query_prepare(query, &stmt);
2148         if (NULL == stmt) {
2149                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
2150                 ctsvc_end_trans(false);
2151                 return ret;
2152         }
2153
2154         if (contact->display_name)
2155                 ctsvc_stmt_bind_text(stmt, 1, contact->display_name);
2156         if (contact->reverse_display_name)
2157                 ctsvc_stmt_bind_text(stmt, 2, contact->reverse_display_name);
2158         if (contact->sort_name)
2159                 ctsvc_stmt_bind_text(stmt, 3, contact->sort_name);
2160         if (contact->reverse_sort_name)
2161                 ctsvc_stmt_bind_text(stmt, 4, contact->reverse_sort_name);
2162         if (contact->sortkey)
2163                 ctsvc_stmt_bind_text(stmt, 5, contact->sortkey);
2164         if (contact->reverse_sortkey)
2165                 ctsvc_stmt_bind_text(stmt, 6, contact->reverse_sortkey);
2166         if (contact->uid)
2167                 ctsvc_stmt_bind_text(stmt, 7, contact->uid);
2168         if (contact->ringtone_path)
2169                 ctsvc_stmt_bind_text(stmt, 8, contact->ringtone_path);
2170         if (contact->vibration)
2171                 ctsvc_stmt_bind_text(stmt, 9, contact->vibration);
2172         if (contact->message_alert)
2173                 ctsvc_stmt_bind_text(stmt, 10, contact->message_alert);
2174         if (contact->image_thumbnail_path)
2175                 ctsvc_stmt_bind_text(stmt, 11, contact->image_thumbnail_path);
2176
2177         ret = ctsvc_stmt_step(stmt);
2178         if (CONTACTS_ERROR_NONE != ret) {
2179                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
2180                 ctsvc_stmt_finalize(stmt);
2181                 ctsvc_end_trans(false);
2182                 return ret;
2183         }
2184         ctsvc_stmt_finalize(stmt);
2185
2186         /* Insert group Info */
2187         if (contact->grouprelations) {
2188                 rel_changed = __ctsvc_contact_insert_grouprel(contact->id, (contacts_list_h)contact->grouprelations);
2189                 if (rel_changed < CONTACTS_ERROR_NONE) {
2190                         ERR("__ctsvc_contact_insert_grouprel() Fail(%d)", rel_changed);
2191                         ctsvc_end_trans(false);
2192                         return rel_changed;
2193                 }
2194         }
2195
2196         ret = __ctsvc_contact_insert_search_data(contact->id, need_insert_lookup);
2197         if (ret != CONTACTS_ERROR_NONE) {
2198                 ERR("__ctsvc_contact_insert_search_data() Fail(%d)", ret);
2199                 ctsvc_end_trans(false);
2200                 return ret;
2201         }
2202
2203         /* person aggregation when auto_linked */
2204         if (auto_linked)
2205                 ctsvc_person_aggregate(contact->person_id);
2206
2207 #ifdef ENABLE_LOG_FEATURE
2208         /* update phonelog */
2209         if (contact->numbers) {
2210                 int count;
2211                 ret = contacts_list_get_count((contacts_list_h)contact->numbers, &count);
2212                 contacts_list_first((contacts_list_h)contact->numbers);
2213                 if (0 < count) {
2214                         ctsvc_number_s *number_record;
2215                         do {
2216                                 contacts_list_get_current_record_p((contacts_list_h)contact->numbers, (contacts_record_h*)&number_record);
2217                                 if (number_record->number)
2218                                         ctsvc_db_phone_log_update_person_id(number_record->number, -1, contact->person_id, false);
2219                         } while (CONTACTS_ERROR_NONE == contacts_list_next((contacts_list_h)contact->numbers));
2220                 }
2221         }
2222 #endif /* ENABLE_LOG_FEATURE */
2223         if (rel_changed)
2224                 ctsvc_set_group_rel_noti();
2225         ctsvc_set_contact_noti();
2226
2227         ret = ctsvc_end_trans(true);
2228         RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "contacts_svc_end_trans() Fail(%d)", ret);
2229
2230         return CONTACTS_ERROR_NONE;
2231 }
2232
2233 static int __ctsvc_db_contact_replace_record(contacts_record_h record, int contact_id)
2234 {
2235         CTS_FN_CALL;
2236         int ret, len;
2237         int rel_changed = 0;
2238         int person_id;
2239         int addressbook_id;
2240         char query[CTS_SQL_MAX_LEN] = {0};
2241         ctsvc_contact_s *contact = (ctsvc_contact_s*)record;
2242         cts_stmt stmt = NULL;
2243         int version;
2244
2245         ret = ctsvc_begin_trans();
2246         RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
2247
2248         snprintf(query, sizeof(query),
2249                         "SELECT addressbook_id, person_id FROM "CTS_TABLE_CONTACTS" "
2250                         "WHERE contact_id = %d AND deleted = 0", contact_id);
2251         ret = ctsvc_query_prepare(query, &stmt);
2252         if (NULL == stmt) {
2253                 ERR("ctsvc_query_prepare fail(%d)", ret);
2254                 ctsvc_end_trans(false);
2255                 return ret;
2256         }
2257         ret = ctsvc_stmt_step(stmt);
2258         if (1 != ret) {
2259                 ERR("The contact_id(%d) is Invalid(%d)", contact_id, ret);
2260                 ctsvc_stmt_finalize(stmt);
2261                 ctsvc_end_trans(false);
2262                 if (CONTACTS_ERROR_NONE == ret)
2263                         return CONTACTS_ERROR_NO_DATA;
2264                 else
2265                         return ret;
2266         }
2267
2268         addressbook_id = ctsvc_stmt_get_int(stmt, 0);
2269         person_id = ctsvc_stmt_get_int(stmt, 1);
2270         ctsvc_stmt_finalize(stmt);
2271
2272         if (false == ctsvc_have_ab_write_permission(addressbook_id, false)) {
2273                 ERR("No permission in this addresbook_id(%d)", addressbook_id);
2274                 ctsvc_end_trans(false);
2275                 return CONTACTS_ERROR_PERMISSION_DENIED;
2276         }
2277
2278         contact->id = contact_id;
2279         contact->person_id = person_id;
2280         ctsvc_contact_make_display_name(contact);
2281         __ctsvc_contact_check_default_data(contact);
2282
2283         /* remove current child data */
2284         snprintf(query, sizeof(query), "DELETE FROM "CTS_TABLE_DATA" WHERE contact_id = %d",
2285                         contact_id);
2286         ret = ctsvc_query_exec(query);
2287         if (CONTACTS_ERROR_NONE != ret) {
2288                 ERR("ctsvc_query_exec() Fail(%d)", ret);
2289                 ctsvc_end_trans(false);
2290                 return ret;
2291         }
2292
2293         ret = __ctsvc_contact_insert_data(contact);
2294         if (CONTACTS_ERROR_NONE != ret) {
2295                 ERR("__ctsvc_contact_insert_data() Fail(%d)", ret);
2296                 ctsvc_end_trans(false);
2297                 return ret;
2298         }
2299
2300         /* remove current child data */
2301         snprintf(query, sizeof(query),
2302                         "DELETE FROM "CTS_TABLE_GROUP_RELATIONS" WHERE contact_id = %d", contact_id);
2303         ret = ctsvc_query_exec(query);
2304         if (CONTACTS_ERROR_NONE != ret) {
2305                 ERR("ctsvc_query_exec() Fail(%d)", ret);
2306                 ctsvc_end_trans(false);
2307                 return ret;
2308         }
2309
2310         if (contact->grouprelations) {
2311                 rel_changed = __ctsvc_contact_insert_grouprel(contact_id,
2312                                 (contacts_list_h)contact->grouprelations);
2313                 if (rel_changed < CONTACTS_ERROR_NONE) {
2314                         ERR("__ctsvc_contact_insert_grouprel() Fail(%d)", rel_changed);
2315                         ctsvc_end_trans(false);
2316                         return rel_changed;
2317                 }
2318         }
2319
2320         /* thumbnail */
2321         if (contact->images) {
2322                 int ret = CONTACTS_ERROR_NONE;
2323                 int count = 0;
2324                 ctsvc_image_s *image;
2325
2326                 contacts_list_get_count((contacts_list_h)contact->images, &count);
2327                 if (count) {
2328                         contacts_list_first((contacts_list_h)contact->images);
2329                         do {
2330                                 ret = contacts_list_get_current_record_p((contacts_list_h)contact->images,
2331                                                 (contacts_record_h*)&image);
2332                                 if (CONTACTS_ERROR_NONE != ret) {
2333                                         ERR("contacts_list_get_current_record_p() Fail(%d)", ret);
2334                                         ctsvc_end_trans(false);
2335                                         return CONTACTS_ERROR_DB;
2336                                 }
2337
2338                                 if (image->is_default)
2339                                         break;
2340                         } while (CONTACTS_ERROR_NONE == contacts_list_next((contacts_list_h)contact->images));
2341
2342                         if ((NULL == contact->image_thumbnail_path && image->path) ||
2343                                         (contact->image_thumbnail_path && NULL == image->path) ||
2344                                         (contact->image_thumbnail_path && image->path && STRING_EQUAL != strcmp(contact->image_thumbnail_path, image->path))) {
2345                                 ctsvc_record_set_property_flag((ctsvc_record_s*)contact, _contacts_contact.image_thumbnail_path, CTSVC_PROPERTY_FLAG_DIRTY);
2346
2347                                 if (ctsvc_contact_check_image_location(image->path))
2348                                         contact->image_thumbnail_path = SAFE_STRDUP(image->path + strlen(CTSVC_CONTACT_IMG_FULL_LOCATION) + 1);
2349                                 else
2350                                         contact->image_thumbnail_path = SAFE_STRDUP(image->path);
2351                         }
2352                 } else if (contact->image_thumbnail_path) {
2353                         free(contact->image_thumbnail_path);
2354                         contact->image_thumbnail_path = NULL;
2355                         if (false == ctsvc_record_check_property_flag((ctsvc_record_s*)contact, _contacts_contact.image_thumbnail_path, CTSVC_PROPERTY_FLAG_DIRTY)) {
2356                                 ctsvc_record_set_property_flag((ctsvc_record_s*)contact, _contacts_contact.image_thumbnail_path, CTSVC_PROPERTY_FLAG_DIRTY);
2357                         } else {
2358                                 if (((ctsvc_record_s*)record)->properties_flags) {
2359                                         int index = _contacts_contact.image_thumbnail_path & 0x000000FF;
2360                                         ((ctsvc_record_s*)record)->properties_flags[index] = 0;
2361                                 }
2362                         }
2363                 }
2364         }
2365         version = ctsvc_get_next_ver();
2366
2367         len = snprintf(query, sizeof(query),
2368                         "UPDATE "CTS_TABLE_CONTACTS" SET changed_ver=%d, changed_time=%d, is_favorite=%d, "
2369                         "has_phonenumber=%d, has_email=%d, display_name=?, "
2370                         "reverse_display_name=?, display_name_source=%d, "
2371                         "display_name_language=%d, reverse_display_name_language=%d, "
2372                         "sort_name=?, reverse_sort_name=?, "
2373                         "sortkey=?, reverse_sortkey=?, uid=?, ringtone_path=?, vibration=?, "
2374                         "message_alert =?, image_thumbnail_path=?",
2375                         version, (int)time(NULL), contact->is_favorite,
2376                         contact->has_phonenumber, contact->has_email,
2377                         contact->display_source_type,
2378                         contact->display_name_language, contact->reverse_display_name_language);
2379
2380         if (ctsvc_record_check_property_flag((ctsvc_record_s*)contact, _contacts_contact.image_thumbnail_path, CTSVC_PROPERTY_FLAG_DIRTY))
2381                 len += snprintf(query+len, sizeof(query)-len, ", image_changed_ver = %d", version);
2382
2383         len += snprintf(query+len, sizeof(query)-len, " WHERE contact_id=%d", contact->id);
2384
2385         ret = ctsvc_query_prepare(query, &stmt);
2386         if (NULL == stmt) {
2387                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
2388                 ctsvc_end_trans(false);
2389                 return ret;
2390         }
2391
2392         if (contact->display_name)
2393                 ctsvc_stmt_bind_text(stmt, 1, contact->display_name);
2394         if (contact->reverse_display_name)
2395                 ctsvc_stmt_bind_text(stmt, 2, contact->reverse_display_name);
2396         if (contact->sort_name)
2397                 ctsvc_stmt_bind_text(stmt, 3, contact->sort_name);
2398         if (contact->reverse_sort_name)
2399                 ctsvc_stmt_bind_text(stmt, 4, contact->reverse_sort_name);
2400         if (contact->sortkey)
2401                 ctsvc_stmt_bind_text(stmt, 5, contact->sortkey);
2402         if (contact->reverse_sortkey)
2403                 ctsvc_stmt_bind_text(stmt, 6, contact->reverse_sortkey);
2404         if (contact->uid)
2405                 ctsvc_stmt_bind_text(stmt, 7, contact->uid);
2406         if (contact->ringtone_path)
2407                 ctsvc_stmt_bind_text(stmt, 8, contact->ringtone_path);
2408         if (contact->vibration)
2409                 ctsvc_stmt_bind_text(stmt, 9, contact->vibration);
2410         if (contact->message_alert)
2411                 ctsvc_stmt_bind_text(stmt, 10, contact->message_alert);
2412         if (contact->image_thumbnail_path)
2413                 ctsvc_stmt_bind_text(stmt, 11, contact->image_thumbnail_path);
2414
2415         ret = ctsvc_stmt_step(stmt);
2416         if (CONTACTS_ERROR_NONE != ret) {
2417                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
2418                 ctsvc_stmt_finalize(stmt);
2419                 ctsvc_end_trans(false);
2420                 return ret;
2421         }
2422         ctsvc_stmt_finalize(stmt);
2423
2424         ctsvc_set_contact_noti();
2425         if (0 < rel_changed)
2426                 ctsvc_set_group_rel_noti();
2427
2428         __ctsvc_contact_update_search_data(contact->id, true);
2429         ctsvc_db_update_person((contacts_record_h)contact);
2430
2431         ret = ctsvc_end_trans(true);
2432
2433         if (ret < CONTACTS_ERROR_NONE)
2434                 return ret;
2435         else
2436                 return CONTACTS_ERROR_NONE;
2437 }
2438
2439 ctsvc_db_plugin_info_s ctsvc_db_plugin_contact = {
2440         .is_query_only = false,
2441         .insert_record = __ctsvc_db_contact_insert_record,
2442         .get_record = __ctsvc_db_contact_get_record,
2443         .update_record = __ctsvc_db_contact_update_record,
2444         .delete_record = __ctsvc_db_contact_delete_record,
2445         .get_all_records = __ctsvc_db_contact_get_all_records,
2446         .get_records_with_query = __ctsvc_db_contact_get_records_with_query,
2447         .insert_records = NULL,
2448         .update_records = NULL,
2449         .delete_records = NULL,
2450         .get_count = NULL,
2451         .get_count_with_query = NULL,
2452         .replace_record = __ctsvc_db_contact_replace_record,
2453         .replace_records = NULL,
2454 };
2455