[SVACE Issue Fixes]
[platform/core/pim/contacts-service.git] / server / db / ctsvc_db_plugin_person_helper.c
1 /*
2  * Contacts Service
3  *
4  * Copyright (c) 2010 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include "contacts.h"
21 #include "ctsvc_internal.h"
22 #include "ctsvc_db_schema.h"
23 #include "ctsvc_db_sqlite.h"
24 #include "ctsvc_db_access_control.h"
25 #include "ctsvc_db_plugin_person_helper.h"
26 #include "ctsvc_localize.h"
27 #include "ctsvc_localize_utils.h"
28 #include "ctsvc_normalize.h"
29 #include "ctsvc_db_init.h"
30 #include "ctsvc_db_utils.h"
31 #include "ctsvc_db_query.h"
32 #include "ctsvc_record.h"
33 #include "ctsvc_notification.h"
34 #include "ctsvc_notify.h"
35 #include "ctsvc_utils_string.h"
36
37 #ifdef _CONTACTS_IPC_SERVER
38 #include "ctsvc_server_change_subject.h"
39 #endif
40
41 int ctsvc_db_person_create_record_from_stmt_with_projection(cts_stmt stmt,
42                 unsigned int *projection,
43                 int projection_count,
44                 bool is_snippet,
45                 const char *keyword,
46                 const char *start_match,
47                 const char *end_match,
48                 int token_number,
49                 contacts_record_h *record)
50 {
51         ctsvc_person_s *person;
52         char full_path[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
53
54         contacts_record_create(_contacts_person._uri, record);
55         person = (ctsvc_person_s*)*record;
56
57         int i;
58         for (i = 0; i < projection_count; i++) {
59                 char *temp;
60                 int property_id = projection[i];
61
62                 switch (property_id) {
63                 case CTSVC_PROPERTY_PERSON_ID:
64                         person->person_id = ctsvc_stmt_get_int(stmt, i);
65                         break;
66                 case CTSVC_PROPERTY_PERSON_DISPLAY_NAME:
67                         temp = ctsvc_stmt_get_text(stmt, i);
68                         free(person->display_name);
69                         person->display_name = SAFE_STRDUP(temp);
70                         break;
71                 case CTSVC_PROPERTY_PERSON_DISPLAY_NAME_INDEX:
72                         temp = ctsvc_stmt_get_text(stmt, i);
73                         free(person->display_name_index);
74                         person->display_name_index = SAFE_STRDUP(temp);
75                         break;
76                 case CTSVC_PROPERTY_PERSON_DISPLAY_CONTACT_ID:
77                         person->name_contact_id = ctsvc_stmt_get_int(stmt, i);
78                         break;
79                 case CTSVC_PROPERTY_PERSON_RINGTONE:
80                         temp = ctsvc_stmt_get_text(stmt, i);
81                         free(person->ringtone_path);
82                         person->ringtone_path = SAFE_STRDUP(temp);
83                         break;
84                 case CTSVC_PROPERTY_PERSON_IMAGE_THUMBNAIL:
85                         temp = ctsvc_stmt_get_text(stmt, i);
86                         if (temp && *temp) {
87                                 snprintf(full_path, sizeof(full_path), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, temp);
88                                 free(person->image_thumbnail_path);
89                                 person->image_thumbnail_path = strdup(full_path);
90                         }
91                         break;
92                 case CTSVC_PROPERTY_PERSON_VIBRATION:
93                         temp = ctsvc_stmt_get_text(stmt, i);
94                         free(person->vibration);
95                         person->vibration = SAFE_STRDUP(temp);
96                         break;
97                 case CTSVC_PROPERTY_PERSON_MESSAGE_ALERT:
98                         temp = ctsvc_stmt_get_text(stmt, i);
99                         free(person->message_alert);
100                         person->message_alert = SAFE_STRDUP(temp);
101                         break;
102                 case CTSVC_PROPERTY_PERSON_STATUS:
103                         temp = ctsvc_stmt_get_text(stmt, i);
104                         free(person->status);
105                         person->status = SAFE_STRDUP(temp);
106                         break;
107                 case CTSVC_PROPERTY_PERSON_IS_FAVORITE:
108                         person->is_favorite = ctsvc_stmt_get_int(stmt, i);
109                         break;
110                 case CTSVC_PROPERTY_PERSON_HAS_PHONENUMBER:
111                         person->has_phonenumber = ctsvc_stmt_get_int(stmt, i);
112                         break;
113                 case CTSVC_PROPERTY_PERSON_HAS_EMAIL:
114                         person->has_email = ctsvc_stmt_get_int(stmt, i);
115                         break;
116                 case CTSVC_PROPERTY_PERSON_LINK_COUNT:
117                         person->link_count = ctsvc_stmt_get_int(stmt, i);
118                         break;
119                 case CTSVC_PROPERTY_PERSON_ADDRESSBOOK_IDS:
120                         temp = ctsvc_stmt_get_text(stmt, i);
121                         free(person->addressbook_ids);
122                         person->addressbook_ids = SAFE_STRDUP(temp);
123                         break;
124                 case CTSVC_PROPERTY_PERSON_FAVORITE_PRIORITY:
125                         person->favorite_prio = ctsvc_stmt_get_dbl(stmt, i);
126                         break;
127                 case CTSVC_PROPERTY_PERSON_SNIPPET_TYPE:
128                         person->snippet_type = ctsvc_stmt_get_int(stmt, i);
129                         break;
130                 case CTSVC_PROPERTY_PERSON_SNIPPET_STRING:
131                         temp = ctsvc_stmt_get_text(stmt, i);
132                         free(person->snippet_string);
133                         person->snippet_string = ctsvc_utils_get_modified_str(temp, is_snippet,
134                                         keyword, start_match, end_match, token_number);
135                         if (NULL == person->snippet_string)
136                                 person->snippet_string = SAFE_STRDUP(temp);
137                         break;
138                 default:
139                         ASSERT_NOT_REACHED("property_id(0x%0x) is not supported in value(person)", property_id);
140                         return CONTACTS_ERROR_INVALID_PARAMETER;
141                 }
142         }
143         return CONTACTS_ERROR_NONE;
144 }
145
146
147 int ctsvc_db_person_create_record_from_stmt_with_query(cts_stmt stmt, contacts_query_h query, contacts_record_h *record)
148 {
149         RETV_IF(NULL == query, CONTACTS_ERROR_INVALID_PARAMETER);
150         ctsvc_query_s *s_query = (ctsvc_query_s*)query;
151
152         if (0 == s_query->projection_count) {
153                 int i;
154                 unsigned int *projection = malloc(sizeof(unsigned int)*s_query->property_count);
155                 if (NULL == projection) {
156                         /* LCOV_EXCL_START */
157                         ERR("malloc() Fail");
158                         return CONTACTS_ERROR_OUT_OF_MEMORY;
159                         /* LCOV_EXCL_STOP */
160                 }
161
162                 for (i = 0; i < s_query->property_count; i++)
163                         projection[i] = s_query->properties[i].property_id;
164
165                 int ret = ctsvc_db_person_create_record_from_stmt_with_projection(stmt,
166                                 projection, s_query->property_count, false, NULL, NULL, NULL, -1, record);
167
168                 free(projection);
169
170                 return ret;
171         } else {
172                 return ctsvc_db_person_create_record_from_stmt_with_projection(stmt,
173                                 s_query->projection, s_query->projection_count, false, NULL, NULL, NULL,
174                                 -1, record);
175         }
176
177 }
178
179 int ctsvc_db_person_create_record_from_stmt(cts_stmt stmt, contacts_record_h *record)
180 {
181         int ret;
182         int i;
183         char *temp;
184         ctsvc_person_s *person;
185
186         i = 0;
187         ret = contacts_record_create(_contacts_person._uri, record);
188         RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "contacts_record_create Fail(%d)", ret);
189         person = (ctsvc_person_s*)*record;
190         person->person_id = ctsvc_stmt_get_int(stmt, i++);
191
192         temp = ctsvc_stmt_get_text(stmt, i++);
193         person->display_name = SAFE_STRDUP(temp);
194         temp = ctsvc_stmt_get_text(stmt, i++);
195         person->display_name_index = SAFE_STRDUP(temp);
196         person->name_contact_id = ctsvc_stmt_get_int(stmt, i++);
197
198         temp = ctsvc_stmt_get_text(stmt, i++);
199         if (temp && *temp) {
200                 char full_path[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
201                 snprintf(full_path, sizeof(full_path), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, temp);
202                 person->image_thumbnail_path = strdup(full_path);
203         }
204
205         temp = ctsvc_stmt_get_text(stmt, i++);
206         person->ringtone_path = SAFE_STRDUP(temp);
207         temp = ctsvc_stmt_get_text(stmt, i++);
208         person->vibration = SAFE_STRDUP(temp);
209         temp = ctsvc_stmt_get_text(stmt, i++);
210         person->message_alert = SAFE_STRDUP(temp);
211         temp = ctsvc_stmt_get_text(stmt, i++);
212         person->status = SAFE_STRDUP(temp);
213
214         person->link_count = ctsvc_stmt_get_int(stmt, i++);
215         temp = ctsvc_stmt_get_text(stmt, i++);
216         person->addressbook_ids = SAFE_STRDUP(temp);
217
218         person->has_phonenumber = ctsvc_stmt_get_int(stmt, i++);
219         person->has_email = ctsvc_stmt_get_int(stmt, i++);
220         person->is_favorite = ctsvc_stmt_get_int(stmt, i++);
221         person->favorite_prio = ctsvc_stmt_get_dbl(stmt, i++);
222         return CONTACTS_ERROR_NONE;
223 }
224
225 static inline const char* __ctsvc_get_image_filename(const char *src)
226 {
227         const char *dir = CTSVC_CONTACT_IMG_FULL_LOCATION;
228         int pos = 0;
229
230         if (NULL == dir)
231                 return src;
232
233         while (dir[pos] == src[pos])
234                 pos++;
235
236         if ('/' == src[pos])
237                 return src + pos + 1;
238
239         return src+pos;
240 }
241
242 int ctsvc_db_person_set_favorite(int person_id, bool set, bool propagate)
243 {
244         int ret;
245         double prio = 0.0;
246         cts_stmt stmt = NULL;
247         char query[CTS_SQL_MIN_LEN] = {0};
248
249         if (set) {
250                 snprintf(query, sizeof(query),
251                                 "SELECT MAX(favorite_prio) FROM "CTS_TABLE_FAVORITES);
252
253                 ret = ctsvc_query_prepare(query, &stmt);
254                 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
255
256                 ret = ctsvc_stmt_step(stmt);
257                 if (1 /*CTS_TRUE*/ == ret) {
258                         prio = ctsvc_stmt_get_dbl(stmt, 0);
259                 } else if (CONTACTS_ERROR_NONE != ret) {
260                         /* LCOV_EXCL_START */
261                         ERR("ctsvc_stmt_step() Fail(%d)", ret);
262                         ctsvc_stmt_finalize(stmt);
263                         return ret;
264                         /* LCOV_EXCL_STOP */
265                 }
266                 ctsvc_stmt_finalize(stmt);
267
268                 prio = prio + 1.0;
269                 snprintf(query, sizeof(query),
270                                 "INSERT OR REPLACE INTO "CTS_TABLE_FAVORITES" values(%d, %f)", person_id, prio);
271         } else {
272                 snprintf(query, sizeof(query),
273                                 "DELETE FROM "CTS_TABLE_FAVORITES" WHERE person_id = %d", person_id);
274         }
275
276         ret = ctsvc_query_exec(query);
277         if (CONTACTS_ERROR_NONE != ret) {
278                 /* LCOV_EXCL_START */
279                 ERR("ctsvc_query_exec() Fail(%d)", ret);
280                 return ret;
281                 /* LCOV_EXCL_STOP */
282         }
283
284         if (propagate) {
285                 snprintf(query, sizeof(query),
286                                 "UPDATE "CTS_TABLE_CONTACTS" SET is_favorite=%d, "
287                                 "changed_time=%d, changed_ver=%d WHERE "
288                                 "person_id=%d AND deleted = 0",
289                                 set ? 1 : 0, (int)time(NULL), ctsvc_get_next_ver(),
290                                 person_id);
291                 ret = ctsvc_query_exec(query);
292                 if (CONTACTS_ERROR_NONE != ret) {
293                         /* LCOV_EXCL_START */
294                         ERR("ctsvc_query_exec() Fail(%d)", ret);
295                         return ret;
296                         /* LCOV_EXCL_STOP */
297                 }
298         }
299
300         return CONTACTS_ERROR_NONE;
301 }
302
303 int ctsvc_db_insert_person(contacts_record_h record)
304 {
305         int ret, index;
306         cts_stmt stmt = NULL;
307         char query[CTS_SQL_MIN_LEN] = {0};
308         int version;
309         ctsvc_contact_s *contact = (ctsvc_contact_s*)record;
310         char *status = NULL;
311
312         snprintf(query, sizeof(query),
313                         "SELECT status FROM %s "
314                         "WHERE contact_id=%d "
315                         "ORDER BY timestamp DESC LIMIT 1",
316                         CTS_TABLE_ACTIVITIES, contact->id);
317         ret = ctsvc_query_prepare(query, &stmt);
318         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
319
320         if (1 == ctsvc_stmt_step(stmt))
321                 status = SAFE_STRDUP(ctsvc_stmt_get_text(stmt, 0));
322         ctsvc_stmt_finalize(stmt);
323
324         version = ctsvc_get_next_ver();
325         snprintf(query, sizeof(query),
326                         "INSERT INTO "CTS_TABLE_PERSONS"(name_contact_id, created_ver, changed_ver, "
327                         "has_phonenumber, has_email, ringtone_path, vibration, message_alert, status, "
328                         "image_thumbnail_path, link_count, addressbook_ids) "
329                         "VALUES(%d, %d, %d, %d, %d, ?, ?, ?, ?, ?, 1, '%d') ",
330                         contact->id, version, version,
331                         contact->has_phonenumber, contact->has_email, contact->addressbook_id);
332
333         ret = ctsvc_query_prepare(query, &stmt);
334         if (NULL == stmt) {
335                 /* LCOV_EXCL_START */
336                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
337                 free(status);
338                 return ret;
339                 /* LCOV_EXCL_STOP */
340         }
341         if (contact->ringtone_path)
342                 ctsvc_stmt_bind_text(stmt, 1, contact->ringtone_path);
343         if (contact->vibration)
344                 ctsvc_stmt_bind_text(stmt, 2, contact->vibration);
345         if (contact->message_alert)
346                 ctsvc_stmt_bind_text(stmt, 3, contact->message_alert);
347         if (status)
348                 ctsvc_stmt_bind_text(stmt, 4, status);
349         if (contact->image_thumbnail_path) {
350                 ctsvc_stmt_bind_text(stmt, 5,
351                                 __ctsvc_get_image_filename(contact->image_thumbnail_path));
352         }
353
354         ret = ctsvc_stmt_step(stmt);
355         if (CONTACTS_ERROR_NONE != ret) {
356                 /* LCOV_EXCL_START */
357                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
358                 ctsvc_stmt_finalize(stmt);
359                 free(status);
360                 return ret;
361                 /* LCOV_EXCL_STOP */
362         }
363         index = ctsvc_db_get_last_insert_id();
364
365         ctsvc_stmt_finalize(stmt);
366
367         snprintf(query, sizeof(query),
368                         "UPDATE "CTS_TABLE_DATA" SET is_primary_default = 1 "
369                         "WHERE is_default = 1 AND contact_id = %d  AND is_my_profile = 0", contact->id);
370
371         ret = ctsvc_query_exec(query);
372         if (CONTACTS_ERROR_NONE != ret) {
373                 /* LCOV_EXCL_START */
374                 ERR("ctsvc_query_exec() Fail(%d)", ret);
375                 free(status);
376                 return ret;
377                 /* LCOV_EXCL_STOP */
378         }
379
380         /* set favorite */
381         if (contact->is_favorite) {
382                 ret = ctsvc_db_person_set_favorite(index, contact->is_favorite, false);
383                 if (CONTACTS_ERROR_NONE != ret) {
384                         /* LCOV_EXCL_START */
385                         ERR("ctsvc_db_person_set_favorite() Fail(%d)", ret);
386                         return ret;
387                         /* LCOV_EXCL_STOP */
388                 }
389         }
390
391         free(status);
392         ctsvc_set_person_noti();
393 #ifdef _CONTACTS_IPC_SERVER
394         ctsvc_change_subject_add_changed_person_id(CONTACTS_CHANGE_INSERTED, index);
395 #endif
396
397         return index;
398 }
399
400 static inline int __ctsvc_db_update_person_default(int person_id, int datatype)
401 {
402         int ret, data_id;
403         cts_stmt stmt = NULL;
404         char query[CTS_SQL_MIN_LEN] = {0};
405         char *temp = NULL;
406         char *image_path = NULL;
407
408         snprintf(query, sizeof(query),
409                         "SELECT D.id FROM "CTS_TABLE_CONTACTS" C, "CTS_TABLE_DATA" D "
410                         "ON C.contact_id = D.contact_id AND C.deleted = 0 "
411                         "WHERE C.person_id=%d AND D.datatype=%d AND is_primary_default=1 AND D.is_my_profile = 0",
412                         person_id, datatype);
413
414         ret = ctsvc_query_get_first_int_result(query, &data_id);
415         if (CONTACTS_ERROR_NO_DATA == ret) {
416                 snprintf(query, sizeof(query),
417                                 "SELECT D.id, D.data3 FROM "CTS_TABLE_CONTACTS" C, "CTS_TABLE_DATA" D "
418                                 "ON C.contact_id = D.contact_id AND C.deleted = 0 "
419                                 "WHERE C.person_id=%d AND D.datatype=%d AND D.is_default=1 AND D.is_my_profile = 0 ORDER BY D.id",
420                                 person_id, datatype);
421
422                 ret = ctsvc_query_prepare(query, &stmt);
423                 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
424
425                 ret = ctsvc_stmt_step(stmt);
426                 if (1 == ret) {
427                         data_id = ctsvc_stmt_get_int(stmt, 0);
428
429                         snprintf(query, sizeof(query),
430                                         "UPDATE "CTS_TABLE_DATA" SET is_primary_default=1 WHERE id=%d",
431                                         data_id);
432
433                         ret = ctsvc_query_exec(query);
434                         if (CONTACTS_ERROR_NONE != ret) {
435                                 /* LCOV_EXCL_START */
436                                 ERR("ctsvc_query_exec() Fail(%d)", ret);
437                                 ctsvc_stmt_finalize(stmt);
438                                 return ret;
439                                 /* LCOV_EXCL_STOP */
440                         }
441
442                         if (CONTACTS_DATA_TYPE_IMAGE == datatype) {
443                                 temp = ctsvc_stmt_get_text(stmt, 1);
444                                 image_path = SAFE_STRDUP(temp);
445                         }
446                 }
447                 ctsvc_stmt_finalize(stmt);
448
449                 if (CONTACTS_DATA_TYPE_IMAGE == datatype) {
450                         if (image_path) {
451                                 char *thumbnail_path = NULL;
452
453                                 snprintf(query, sizeof(query),
454                                                 "UPDATE "CTS_TABLE_PERSONS" SET image_thumbnail_path=? WHERE person_id=%d", person_id);
455                                 ret = ctsvc_query_prepare(query, &stmt);
456                                 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
457                                 thumbnail_path = ctsvc_utils_get_thumbnail_path(image_path, TRUE);
458                                 ctsvc_stmt_bind_text(stmt, 1, thumbnail_path);
459                                 ret = ctsvc_stmt_step(stmt);
460                                 ctsvc_stmt_finalize(stmt);
461                                 free(image_path);
462                                 free(thumbnail_path);
463                                 if (CONTACTS_ERROR_NONE != ret) {
464                                         /* LCOV_EXCL_START */
465                                         ERR("ctsvc_stmt_step() Fail(%d)", ret);
466                                         return ret;
467                                         /* LCOV_EXCL_STOP */
468                                 }
469                         }
470                 }
471         }
472
473         return CONTACTS_ERROR_NONE;
474 }
475
476 static bool __ctsvc_get_has_column(int person_id, const char *culumn)
477 {
478         int ret;
479         int contact_count = 0;
480         char query[CTS_SQL_MIN_LEN] = {0};
481
482         snprintf(query, sizeof(query),
483                         "SELECT count(contact_id) FROM "CTS_TABLE_CONTACTS" "
484                         "WHERE person_id=%d AND %s=1 AND deleted = 0",
485                         person_id, culumn);
486
487         ret = ctsvc_query_get_first_int_result(query, &contact_count);
488         RETV_IF(CONTACTS_ERROR_NONE != ret, false);
489
490         if (contact_count)
491                 return true;
492         return false;
493 }
494
495 static int __ctsvc_get_thumbnail_contact_id(int person_id)
496 {
497         int ret;
498         int contact_id = 0;
499         char query[CTS_SQL_MIN_LEN] = {0};
500
501         snprintf(query, sizeof(query),
502                         "SELECT D.contact_id FROM "CTS_TABLE_CONTACTS" C, "CTS_TABLE_DATA" D "
503                         "ON C.contact_id = D.contact_id AND C.deleted = 0 "
504                         "WHERE C.person_id=%d AND D.datatype=%d AND is_primary_default=1 AND D.is_my_profile = 0",
505                         person_id, CONTACTS_DATA_TYPE_IMAGE);
506         ret = ctsvc_query_get_first_int_result(query, &contact_id);
507         RETV_IF(CONTACTS_ERROR_NONE != ret, -1);
508         return contact_id;
509 }
510
511 int ctsvc_db_update_person(contacts_record_h record)
512 {
513         int ret, i = 1, len = 0;
514         cts_stmt stmt = NULL;
515         char query[CTS_SQL_MIN_LEN] = {0};
516         ctsvc_contact_s *contact = (ctsvc_contact_s*)record;
517         bool has_phonenumber = false, has_email = false;
518         int thumbnail_contact_id = 0;
519         int person_id = 0;
520         int is_favorite = 0;
521
522         ret = ctsvc_begin_trans();
523         RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
524
525         __ctsvc_db_update_person_default(contact->person_id, CONTACTS_DATA_TYPE_NUMBER);
526         __ctsvc_db_update_person_default(contact->person_id, CONTACTS_DATA_TYPE_EMAIL);
527         __ctsvc_db_update_person_default(contact->person_id, CONTACTS_DATA_TYPE_IMAGE);
528
529         has_phonenumber = __ctsvc_get_has_column(contact->person_id, "has_phonenumber");
530         has_email = __ctsvc_get_has_column(contact->person_id, "has_email");
531         thumbnail_contact_id = __ctsvc_get_thumbnail_contact_id(contact->person_id);
532
533         len = snprintf(query, sizeof(query),
534                         "UPDATE "CTS_TABLE_PERSONS" SET changed_ver=%d, has_phonenumber=%d, has_email=%d ",
535                         ctsvc_get_next_ver(), has_phonenumber, has_email);
536
537         if (ctsvc_record_check_property_flag((ctsvc_record_s*)record, _contacts_contact.ringtone_path, CTSVC_PROPERTY_FLAG_DIRTY))
538                 len += snprintf(query+len, sizeof(query)-len, ", ringtone_path=?");
539         if (ctsvc_record_check_property_flag((ctsvc_record_s*)record, _contacts_contact.vibration, CTSVC_PROPERTY_FLAG_DIRTY))
540                 len += snprintf(query+len, sizeof(query)-len, ", vibration=?");
541         if (ctsvc_record_check_property_flag((ctsvc_record_s*)record, _contacts_contact.message_alert, CTSVC_PROPERTY_FLAG_DIRTY))
542                 len += snprintf(query+len, sizeof(query)-len, ", message_alert=?");
543         if (ctsvc_record_check_property_flag((ctsvc_record_s*)record, _contacts_contact.image_thumbnail_path, CTSVC_PROPERTY_FLAG_DIRTY) &&
544                         (contact->id == thumbnail_contact_id || thumbnail_contact_id == -1))
545                 len += snprintf(query+len, sizeof(query)-len, ", image_thumbnail_path=?");
546
547         snprintf(query+len, sizeof(query)-len,
548                         " WHERE person_id=%d", contact->person_id);
549
550         ret = ctsvc_query_prepare(query, &stmt);
551         if (NULL == stmt) {
552                 /* LCOV_EXCL_START */
553                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
554                 ctsvc_end_trans(false);
555                 return ret;
556                 /* LCOV_EXCL_STOP */
557         }
558
559         if (ctsvc_record_check_property_flag((ctsvc_record_s*)record, _contacts_contact.ringtone_path, CTSVC_PROPERTY_FLAG_DIRTY)) {
560                 if (contact->ringtone_path)
561                         ctsvc_stmt_bind_text(stmt, i, contact->ringtone_path);
562                 i++;
563         }
564         if (ctsvc_record_check_property_flag((ctsvc_record_s*)record, _contacts_contact.vibration, CTSVC_PROPERTY_FLAG_DIRTY)) {
565                 if (contact->vibration)
566                         ctsvc_stmt_bind_text(stmt, i, contact->vibration);
567                 i++;
568         }
569         if (ctsvc_record_check_property_flag((ctsvc_record_s*)record, _contacts_contact.message_alert, CTSVC_PROPERTY_FLAG_DIRTY)) {
570                 if (contact->message_alert)
571                         ctsvc_stmt_bind_text(stmt, i, contact->message_alert);
572                 i++;
573         }
574         if (ctsvc_record_check_property_flag((ctsvc_record_s*)record, _contacts_contact.image_thumbnail_path, CTSVC_PROPERTY_FLAG_DIRTY) &&
575                         (contact->id == thumbnail_contact_id || thumbnail_contact_id == -1)) {
576                 if (contact->image_thumbnail_path)
577                         ctsvc_stmt_bind_text(stmt, i, contact->image_thumbnail_path);
578                 i++;
579         }
580
581         ret = ctsvc_stmt_step(stmt);
582         if (CONTACTS_ERROR_NONE != ret) {
583                 /* LCOV_EXCL_START */
584                 ERR("ctsvc_stmt_step() Fail(%d)", ret);
585                 ctsvc_stmt_finalize(stmt);
586                 ctsvc_end_trans(false);
587                 return ret;
588                 /* LCOV_EXCL_STOP */
589         }
590         ctsvc_stmt_finalize(stmt);
591
592         /* update favorite */
593         snprintf(query, sizeof(query),
594                         "SELECT is_favorite FROM "CTS_TABLE_CONTACTS" WHERE contact_id =%d ", contact->id);
595         ret = ctsvc_query_get_first_int_result(query, &is_favorite);
596         if (ret < CONTACTS_ERROR_NONE) {
597                 /* LCOV_EXCL_START */
598                 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
599                 ctsvc_end_trans(false);
600                 return ret;
601                 /* LCOV_EXCL_STOP */
602         }
603
604         snprintf(query, sizeof(query),
605                         "SELECT person_id FROM "CTS_TABLE_FAVORITES" WHERE person_id =%d ", contact->person_id);
606         ret = ctsvc_query_get_first_int_result(query, &person_id);
607         if (CONTACTS_ERROR_NO_DATA == ret && is_favorite) {
608                 ret = ctsvc_db_person_set_favorite(contact->person_id, true, false);
609                 if (CONTACTS_ERROR_NONE != ret) {
610                         /* LCOV_EXCL_START */
611                         ERR("ctsvc_db_person_set_favorite() Fail(%d)", ret);
612                         ctsvc_end_trans(false);
613                         return ret;
614                         /* LCOV_EXCL_STOP */
615                 }
616         } else if (CONTACTS_ERROR_NONE == ret && false == is_favorite) {
617                 snprintf(query, sizeof(query),
618                                 "SELECT person_id FROM "CTS_TABLE_CONTACTS" WHERE person_id =%d AND is_favorite = 1", contact->person_id);
619                 ret = ctsvc_query_get_first_int_result(query, &person_id);
620                 if (CONTACTS_ERROR_NO_DATA == ret) {
621                         ret = ctsvc_db_person_set_favorite(contact->person_id, false, false);
622                         if (CONTACTS_ERROR_NONE != ret) {
623                                 /* LCOV_EXCL_START */
624                                 ERR("ctsvc_db_person_set_favorite() Fail(%d)", ret);
625                                 ctsvc_end_trans(false);
626                                 return ret;
627                                 /* LCOV_EXCL_STOP */
628                         }
629                 } else if (CONTACTS_ERROR_NONE != ret) {
630                         /* LCOV_EXCL_START */
631                         ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
632                         ctsvc_end_trans(false);
633                         return ret;
634                         /* LCOV_EXCL_STOP */
635                 }
636         } else if (ret < CONTACTS_ERROR_NONE && CONTACTS_ERROR_NO_DATA != ret) {
637                 /* LCOV_EXCL_START */
638                 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
639                 ctsvc_end_trans(false);
640                 return ret;
641                 /* LCOV_EXCL_STOP */
642         }
643
644         ctsvc_set_person_noti();
645
646 #ifdef _CONTACTS_IPC_SERVER
647         ctsvc_change_subject_add_changed_person_id(CONTACTS_CHANGE_UPDATED, contact->person_id);
648 #endif
649
650         ret = ctsvc_end_trans(true);
651         if (ret < CONTACTS_ERROR_NONE) {
652                 /* LCOV_EXCL_START */
653                 ERR("ctsvc_end_trans() Fail(%d)", ret);
654                 return ret;
655                 /* LCOV_EXCL_STOP */
656         } else {
657                 return CONTACTS_ERROR_NONE;
658         }
659 }
660
661 /* This function will return group letter of the person */
662 void ctsvc_db_normalize_str_callback(sqlite3_context  *context,
663                 int argc, sqlite3_value **argv)
664 {
665         const char *display_name;
666         int display_name_language = CTSVC_LANG_OTHERS;
667
668         if (argc < 1) {
669                 sqlite3_result_null(context);
670                 return;
671         }
672
673         display_name_language = sqlite3_value_int(argv[1]);
674         if (display_name_language == CTSVC_SORT_OTHERS || display_name_language == CTSVC_SORT_NUMBER) {
675                 sqlite3_result_text(context, "#", 1, SQLITE_TRANSIENT);
676                 return;
677         } else {
678                 display_name = (const char *)sqlite3_value_text(argv[0]);
679                 if (display_name) {
680                         int ret;
681                         char *dest = NULL;
682                         ret = ctsvc_normalize_index(display_name, &dest);
683                         if (ret < CONTACTS_ERROR_NONE) {
684                                 /* LCOV_EXCL_START */
685                                 ERR("ctsvc_normalize_index() Fail(%d)", ret);
686                                 sqlite3_result_null(context);
687                                 return;
688                                 /* LCOV_EXCL_STOP */
689                         }
690                         sqlite3_result_text(context, dest, strlen(dest), SQLITE_TRANSIENT);
691                         free(dest);
692                         return;
693                 }
694         }
695
696         sqlite3_result_null(context);
697         return;
698 }
699