4 * Copyright (c) 2010 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
22 #include "ctsvc_internal.h"
23 #include "ctsvc_db_schema.h"
24 #include "ctsvc_db_sqlite.h"
25 #include "ctsvc_normalize.h"
26 #include "ctsvc_number_utils.h"
27 #include "ctsvc_db_utils.h"
28 #include "ctsvc_list.h"
29 #include "ctsvc_record.h"
30 #include "ctsvc_db_query.h"
31 #include "ctsvc_db_init.h"
32 #include "ctsvc_notification.h"
33 #include "ctsvc_server_setting.h"
34 #include "ctsvc_db_access_control.h"
35 #include "ctsvc_localize_utils.h"
36 #include "ctsvc_server_phonelog.h"
38 #ifdef _CONTACTS_IPC_SERVER
39 #include "ctsvc_server_change_subject.h"
40 #include "ctsvc_server_sim.h"
41 #endif /* _CONTACTS_IPC_SERVER */
44 static int __ctsvc_db_phonelog_value_set(cts_stmt stmt, contacts_record_h *record)
49 ctsvc_phonelog_s *phonelog;
51 ret = contacts_record_create(_contacts_phone_log._uri, record);
52 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "contacts_record_create Fail(%d)", ret);
53 phonelog = (ctsvc_phonelog_s*)*record;
56 phonelog->id = ctsvc_stmt_get_int(stmt, i++);
57 temp = ctsvc_stmt_get_text(stmt, i++);
58 phonelog->address = SAFE_STRDUP(temp);
59 phonelog->person_id = ctsvc_stmt_get_int(stmt, i++);
60 phonelog->log_type = ctsvc_stmt_get_int(stmt, i++);
61 phonelog->log_time = ctsvc_stmt_get_int(stmt, i++);
62 phonelog->extra_data1 = ctsvc_stmt_get_int(stmt, i++);
63 temp = ctsvc_stmt_get_text(stmt, i++);
64 phonelog->extra_data2 = SAFE_STRDUP(temp);
65 #ifdef _CONTACTS_IPC_SERVER
66 phonelog->sim_slot_no = ctsvc_server_sim_get_sim_slot_no_by_info_id(ctsvc_stmt_get_int(stmt, i++));
67 #endif /* _CONTACTS_IPC_SERVER */
68 return CONTACTS_ERROR_NONE;
71 static int __ctsvc_db_phonelog_get_record(int id, contacts_record_h *out_record)
75 char query[CTS_SQL_MAX_LEN] = {0};
76 contacts_record_h record;
78 RETV_IF(NULL == out_record, CONTACTS_ERROR_INVALID_PARAMETER);
81 snprintf(query, sizeof(query),
82 "SELECT id, number, person_id, log_type, log_time, data1, data2, sim_id "
83 "FROM "CTS_TABLE_PHONELOGS" WHERE id = %d", id);
85 ret = ctsvc_query_prepare(query, &stmt);
86 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
88 ret = ctsvc_stmt_step(stmt);
89 if (1 /*CTS_TRUE*/ != ret) {
91 ERR("ctsvc_stmt_step() Fail(%d)", ret);
92 ctsvc_stmt_finalize(stmt);
93 if (CONTACTS_ERROR_NONE == ret)
94 return CONTACTS_ERROR_NO_DATA;
100 ret = __ctsvc_db_phonelog_value_set(stmt, &record);
102 ctsvc_stmt_finalize(stmt);
103 if (CONTACTS_ERROR_NONE != ret) {
104 /* LCOV_EXCL_START */
105 ERR("__ctsvc_db_phonelog_value_set(ALL) Fail(%d)", ret);
110 *out_record = record;
112 return CONTACTS_ERROR_NONE;
115 static int __ctsvc_db_phonelog_update_record(contacts_record_h record)
118 char query[CTS_SQL_MIN_LEN] = {0};
119 ctsvc_phonelog_s *phonelog = (ctsvc_phonelog_s*)record;
120 int ret = CONTACTS_ERROR_NONE;
122 GSList *bind_text = NULL;
123 GSList *cursor = NULL;
125 RETV_IF(NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
126 RETVM_IF(phonelog->id <= 0, CONTACTS_ERROR_INVALID_PARAMETER,
127 "The phone_log has ID(%d)", phonelog->id);
128 RETVM_IF(phonelog->log_type != CONTACTS_PLOG_TYPE_VOICE_INCOMING_SEEN &&
129 phonelog->log_type != CONTACTS_PLOG_TYPE_VIDEO_INCOMING_SEEN, CONTACTS_ERROR_INVALID_PARAMETER,
130 "the type is can not updated(%d)", phonelog->log_type);
131 RETVM_IF(CTSVC_PROPERTY_FLAG_DIRTY != (phonelog->base.property_flag & CTSVC_PROPERTY_FLAG_DIRTY), CONTACTS_ERROR_NONE, "No update");
133 ret = ctsvc_begin_trans();
134 RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
136 snprintf(query, sizeof(query),
137 "SELECT id FROM "CTS_TABLE_PHONELOGS" WHERE id = %d", phonelog->id);
138 ret = ctsvc_query_get_first_int_result(query, &phonelog_id);
139 if (ret != CONTACTS_ERROR_NONE) {
140 /* LCOV_EXCL_START */
141 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
142 ctsvc_end_trans(false);
148 if (CONTACTS_ERROR_NONE != (ret = ctsvc_db_create_set_query(record, &set, &bind_text))) break;
149 if (CONTACTS_ERROR_NONE != (ret = ctsvc_db_update_record_with_set_query(set, bind_text, CTS_TABLE_PHONELOGS, phonelog->id))) break;
151 if (ctsvc_db_change()) {
152 ctsvc_set_phonelog_noti();
153 #ifdef _CONTACTS_IPC_SERVER
154 ctsvc_change_subject_add_changed_phone_log_id(CONTACTS_CHANGE_UPDATED, phonelog->id);
159 CTSVC_RECORD_RESET_PROPERTY_FLAGS((ctsvc_record_s*)record);
163 for (cursor = bind_text; cursor; cursor = cursor->next) {
167 g_slist_free(bind_text);
170 ret = ctsvc_end_trans(true);
171 RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_end_trans() Fail(%d)", ret);
173 return CONTACTS_ERROR_NONE;
176 static int __ctsvc_db_phonelog_delete_record(int id)
180 char query[CTS_SQL_MAX_LEN] = {0};
182 ret = ctsvc_begin_trans();
183 RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
185 snprintf(query, sizeof(query),
186 "SELECT id FROM "CTS_TABLE_PHONELOGS" WHERE id = %d", id);
187 ret = ctsvc_query_get_first_int_result(query, &phonelog_id);
188 if (ret != CONTACTS_ERROR_NONE) {
189 /* LCOV_EXCL_START */
190 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
191 ctsvc_end_trans(false);
196 snprintf(query, sizeof(query), "DELETE FROM %s WHERE id = %d",
197 CTS_TABLE_PHONELOGS, id);
199 ret = ctsvc_query_exec(query);
200 if (CONTACTS_ERROR_NONE != ret) {
201 /* LCOV_EXCL_START */
202 ERR("ctsvc_query_exec() Fail(%d)", ret);
203 ctsvc_end_trans(false);
208 ctsvc_set_phonelog_noti();
210 ret = ctsvc_end_trans(true);
211 if (ret < CONTACTS_ERROR_NONE) {
212 /* LCOV_EXCL_START */
213 ERR("ctsvc_end_trans() Fail(%d)", ret);
217 return CONTACTS_ERROR_NONE;
221 static int __ctsvc_db_phonelog_get_all_records(int offset, int limit,
222 contacts_list_h *out_list)
227 char query[CTS_SQL_MAX_LEN] = {0};
228 contacts_list_h list;
230 len = snprintf(query, sizeof(query),
231 "SELECT id, number, person_id, log_type, log_time, data1, data2, sim_id "
232 "FROM "CTS_TABLE_PHONELOGS);
235 len += snprintf(query+len, sizeof(query)-len, " LIMIT %d", limit);
237 len += snprintf(query+len, sizeof(query)-len, " OFFSET %d", offset);
240 ret = ctsvc_query_prepare(query, &stmt);
241 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
243 contacts_list_create(&list);
244 while ((ret = ctsvc_stmt_step(stmt))) {
245 contacts_record_h record;
247 /* LCOV_EXCL_START */
248 ERR("ctsvc_stmt_step() Fail(%d)", ret);
249 ctsvc_stmt_finalize(stmt);
250 contacts_list_destroy(list, true);
254 __ctsvc_db_phonelog_value_set(stmt, &record);
256 ctsvc_list_prepend(list, record);
258 ctsvc_stmt_finalize(stmt);
259 ctsvc_list_reverse(list);
261 *out_list = (contacts_list_h)list;
262 return CONTACTS_ERROR_NONE;
265 static int __ctsvc_db_phonelog_get_records_with_query(contacts_query_h query, int offset,
266 int limit, contacts_list_h *out_list)
271 ctsvc_query_s *s_query;
273 contacts_list_h list;
274 ctsvc_phonelog_s *phonelog;
276 RETV_IF(NULL == query, CONTACTS_ERROR_INVALID_PARAMETER);
277 s_query = (ctsvc_query_s*)query;
279 ret = ctsvc_db_make_get_records_query_stmt(s_query, offset, limit, &stmt);
280 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_db_make_get_records_query_stmt fail(%d)", ret);
282 contacts_list_create(&list);
283 while ((ret = ctsvc_stmt_step(stmt))) {
284 contacts_record_h record;
286 /* LCOV_EXCL_START */
287 ERR("ctsvc_stmt_step() Fail(%d)", ret);
288 ctsvc_stmt_finalize(stmt);
289 contacts_list_destroy(list, true);
294 contacts_record_create(_contacts_phone_log._uri, &record);
295 phonelog = (ctsvc_phonelog_s*)record;
296 if (0 == s_query->projection_count) {
297 field_count = s_query->property_count;
299 field_count = s_query->projection_count;
301 int err = ctsvc_record_set_projection_flags(record, s_query->projection,
302 s_query->projection_count, s_query->property_count);
303 if (CONTACTS_ERROR_NONE != err)
304 ASSERT_NOT_REACHED("To set projection is Fail.\n");
307 for (i = 0; i < field_count; i++) {
310 if (0 == s_query->projection_count)
311 property_id = s_query->properties[i].property_id;
313 property_id = s_query->projection[i];
315 switch (property_id) {
316 case CTSVC_PROPERTY_PHONELOG_ID:
317 phonelog->id = ctsvc_stmt_get_int(stmt, i);
319 case CTSVC_PROPERTY_PHONELOG_PERSON_ID:
320 phonelog->person_id = ctsvc_stmt_get_int(stmt, i);
322 case CTSVC_PROPERTY_PHONELOG_ADDRESS:
323 temp = ctsvc_stmt_get_text(stmt, i);
324 free(phonelog->address);
325 phonelog->address = SAFE_STRDUP(temp);
327 case CTSVC_PROPERTY_PHONELOG_LOG_TIME:
328 phonelog->log_time = ctsvc_stmt_get_int(stmt, i);
330 case CTSVC_PROPERTY_PHONELOG_LOG_TYPE:
331 phonelog->log_type = ctsvc_stmt_get_int(stmt, i);
333 case CTSVC_PROPERTY_PHONELOG_EXTRA_DATA1:
334 phonelog->extra_data1 = ctsvc_stmt_get_int(stmt, i);
336 case CTSVC_PROPERTY_PHONELOG_EXTRA_DATA2:
337 temp = ctsvc_stmt_get_text(stmt, i);
338 free(phonelog->extra_data2);
339 phonelog->extra_data2 = SAFE_STRDUP(temp);
341 case CTSVC_PROPERTY_PHONELOG_SIM_SLOT_NO:
342 phonelog->sim_slot_no = ctsvc_server_sim_get_sim_slot_no_by_info_id(ctsvc_stmt_get_int(stmt, i));
348 ctsvc_list_prepend(list, record);
351 ctsvc_stmt_finalize(stmt);
352 ctsvc_list_reverse(list);
356 return CONTACTS_ERROR_NONE;
359 static int __ctsvc_db_phonelog_increase_used_count(ctsvc_phonelog_s *phonelog)
363 int type = CONTACTS_USAGE_STAT_TYPE_NONE;
364 char query[CTS_SQL_MIN_LEN] = {0};
366 switch (phonelog->log_type) {
367 case CONTACTS_PLOG_TYPE_VOICE_OUTGOING:
368 case CONTACTS_PLOG_TYPE_VIDEO_OUTGOING:
369 type = CONTACTS_USAGE_STAT_TYPE_OUTGOING_CALL;
371 case CONTACTS_PLOG_TYPE_MMS_OUTGOING:
372 case CONTACTS_PLOG_TYPE_SMS_OUTGOING:
373 type = CONTACTS_USAGE_STAT_TYPE_OUTGOING_MSG;
375 case CONTACTS_PLOG_TYPE_EMAIL_SENT:
376 type = CONTACTS_USAGE_STAT_TYPE_OUTGOING_EMAIL;
378 case CONTACTS_PLOG_TYPE_VOICE_INCOMING:
379 case CONTACTS_PLOG_TYPE_VIDEO_INCOMING:
380 type = CONTACTS_USAGE_STAT_TYPE_INCOMING_CALL;
382 case CONTACTS_PLOG_TYPE_MMS_INCOMING:
383 case CONTACTS_PLOG_TYPE_SMS_INCOMING:
384 type = CONTACTS_USAGE_STAT_TYPE_INCOMING_MSG;
386 case CONTACTS_PLOG_TYPE_EMAIL_RECEIVED:
387 type = CONTACTS_USAGE_STAT_TYPE_INCOMING_EMAIL;
389 case CONTACTS_PLOG_TYPE_VOICE_INCOMING_UNSEEN:
390 case CONTACTS_PLOG_TYPE_VOICE_INCOMING_SEEN:
391 case CONTACTS_PLOG_TYPE_VIDEO_INCOMING_UNSEEN:
392 case CONTACTS_PLOG_TYPE_VIDEO_INCOMING_SEEN:
393 type = CONTACTS_USAGE_STAT_TYPE_MISSED_CALL;
395 case CONTACTS_PLOG_TYPE_VOICE_REJECT:
396 case CONTACTS_PLOG_TYPE_VIDEO_REJECT:
397 type = CONTACTS_USAGE_STAT_TYPE_REJECTED_CALL;
399 case CONTACTS_PLOG_TYPE_VOICE_BLOCKED:
400 case CONTACTS_PLOG_TYPE_VIDEO_BLOCKED:
401 type = CONTACTS_USAGE_STAT_TYPE_BLOCKED_CALL;
404 case CONTACTS_PLOG_TYPE_SMS_BLOCKED:
405 case CONTACTS_PLOG_TYPE_MMS_BLOCKED:
406 type = CONTACTS_USAGE_STAT_TYPE_BLOCKED_MSG;
410 /* LCOV_EXCL_START */
411 ERR("unknown log type (%d)", phonelog->log_type);
412 return CONTACTS_ERROR_INVALID_PARAMETER;
416 snprintf(query, sizeof(query),
417 "SELECT person_id FROM %s WHERE person_id = %d and usage_type = %d ",
418 CTS_TABLE_CONTACT_STAT, phonelog->person_id, type);
420 ret = ctsvc_query_get_first_int_result(query, &id);
421 if (CONTACTS_ERROR_NO_DATA == ret) {
422 snprintf(query, sizeof(query),
423 "INSERT INTO %s(person_id, usage_type, times_used) VALUES(%d, %d, 1)",
424 CTS_TABLE_CONTACT_STAT, phonelog->person_id, type);
426 snprintf(query, sizeof(query),
427 "UPDATE %s SET times_used = times_used + 1 WHERE person_id = %d and usage_type = %d",
428 CTS_TABLE_CONTACT_STAT, phonelog->person_id, type);
431 ret = ctsvc_query_exec(query);
432 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_query_exec() Fail(%d)", ret);
434 return CONTACTS_ERROR_NONE;
437 static int __ctsvc_db_phonelog_insert(ctsvc_phonelog_s *phonelog, int *id)
440 cts_stmt stmt = NULL;
441 char query[CTS_SQL_MAX_LEN] = {0};
443 RETVM_IF((phonelog->log_type < CONTACTS_PLOG_TYPE_NONE
444 || CONTACTS_PLOG_TYPE_EMAIL_SENT < phonelog->log_type)
445 , CONTACTS_ERROR_INVALID_PARAMETER, "phonelog type(%d) is invaid", phonelog->log_type);
447 snprintf(query, sizeof(query), "INSERT INTO "CTS_TABLE_PHONELOGS"("
448 "number, normal_num, minmatch, clean_num, person_id, log_type,log_time, data1, data2, sim_id) "
449 "VALUES(?, ?, ?, ?, ?, %d, %d, %d, ?, ?)",
450 phonelog->log_type, phonelog->log_time, phonelog->extra_data1);
452 ret = ctsvc_query_prepare(query, &stmt);
453 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
455 if (phonelog->address) {
456 ctsvc_stmt_bind_text(stmt, 1, phonelog->address);
457 if (phonelog->log_type < CONTACTS_PLOG_TYPE_EMAIL_RECEIVED) {
458 char clean_num[strlen(phonelog->address) + 1];
459 ret = ctsvc_clean_number(phonelog->address, clean_num, sizeof(clean_num), true);
461 char normal_num[sizeof(clean_num) + 20];
462 ctsvc_stmt_bind_copy_text(stmt, 4, clean_num, strlen(clean_num));
463 ret = ctsvc_normalize_number(clean_num, normal_num, sizeof(normal_num), true);
465 char minmatch[sizeof(normal_num) + 1];
466 ctsvc_stmt_bind_copy_text(stmt, 2, normal_num, strlen(normal_num));
467 ret = ctsvc_get_minmatch_number(normal_num, minmatch, sizeof(minmatch), ctsvc_get_phonenumber_min_match_digit());
468 ctsvc_stmt_bind_copy_text(stmt, 3, minmatch, strlen(minmatch));
474 if (0 < phonelog->person_id)
475 ctsvc_stmt_bind_int(stmt, 5, phonelog->person_id);
477 if (phonelog->extra_data2)
478 ctsvc_stmt_bind_text(stmt, 6, phonelog->extra_data2);
480 if (0 <= phonelog->sim_slot_no) {
482 sim_info_id = ctsvc_server_sim_get_info_id_by_sim_slot_no(phonelog->sim_slot_no);
484 ctsvc_stmt_bind_int(stmt, 7, sim_info_id);
486 ctsvc_stmt_bind_int(stmt, 7, -1);
489 ret = ctsvc_stmt_step(stmt);
490 if (CONTACTS_ERROR_NONE != ret) {
491 /* LCOV_EXCL_START */
492 ERR("ctsvc_stmt_step() Fail(%d)", ret);
493 ctsvc_stmt_finalize(stmt);
498 *id = ctsvc_db_get_last_insert_id();
499 ctsvc_stmt_finalize(stmt);
501 /* update phonelog */
502 ctsvc_db_phone_log_update_person_id(phonelog->address, phonelog->person_id, -1, false, &phonelog->person_id);
504 ctsvc_set_phonelog_noti();
505 return CONTACTS_ERROR_NONE;
508 static int __ctsvc_db_phonelog_insert_record(contacts_record_h record, int *id)
511 ctsvc_phonelog_s *phonelog = (ctsvc_phonelog_s*)record;
513 RETV_IF(NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
514 RETVM_IF(phonelog->id, CONTACTS_ERROR_INVALID_PARAMETER,
515 "The phone_log has ID(%d)", phonelog->id);
517 ret = ctsvc_begin_trans();
518 RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
520 ret = __ctsvc_db_phonelog_insert(phonelog, id);
521 if (CONTACTS_ERROR_NONE != ret) {
522 /* LCOV_EXCL_START */
523 ERR("__ctsvc_db_phonelog_insert() Fail(%d)", ret);
524 ctsvc_end_trans(false);
529 if (0 < phonelog->person_id) {
530 ret = __ctsvc_db_phonelog_increase_used_count(phonelog);
531 WARN_IF(CONTACTS_ERROR_NONE != ret, "__ctsvc_db_phonelog_increase_used_count() Fail(%d)", ret);
534 #ifdef _CONTACTS_IPC_SERVER
535 /* add id for subscribe */
536 ctsvc_change_subject_add_changed_phone_log_id(CONTACTS_CHANGE_INSERTED, *id);
539 ret = ctsvc_end_trans(true);
540 if (ret < CONTACTS_ERROR_NONE) {
541 /* LCOV_EXCL_START */
542 ERR("ctsvc_end_trans() Fail(%d)", ret);
546 return CONTACTS_ERROR_NONE;
549 ctsvc_db_plugin_info_s ctsvc_db_plugin_phonelog = {
550 .is_query_only = false,
551 .insert_record = __ctsvc_db_phonelog_insert_record,
552 .get_record = __ctsvc_db_phonelog_get_record,
553 .update_record = __ctsvc_db_phonelog_update_record,
554 .delete_record = __ctsvc_db_phonelog_delete_record,
555 .get_all_records = __ctsvc_db_phonelog_get_all_records,
556 .get_records_with_query = __ctsvc_db_phonelog_get_records_with_query,
557 .insert_records = NULL,
558 .update_records = NULL,
559 .delete_records = NULL,
561 .get_count_with_query = NULL,
562 .replace_record = NULL,
563 .replace_records = NULL,