enable snippet in searching records
[platform/core/pim/contacts-service.git] / server / ctsvc_server_phonelog.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 "contacts_phone_log_internal.h"
22
23 #include "ctsvc_internal.h"
24 #include "ctsvc_db_schema.h"
25 #include "ctsvc_db_sqlite.h"
26 #include "ctsvc_db_utils.h"
27 #include "ctsvc_notification.h"
28 #include "ctsvc_db_access_control.h"
29 #include "ctsvc_number_utils.h"
30 #include "ctsvc_localize_utils.h"
31 #include "ctsvc_server_setting.h"
32 #include "ctsvc_server_utils.h"
33
34 #ifdef _CONTACTS_IPC_SERVER
35 #include "ctsvc_server_change_subject.h"
36 #include "ctsvc_server_sim.h"
37 #endif /* _CONTACTS_IPC_SERVER */
38
39 int ctsvc_phone_log_reset_statistics()
40 {
41         char query[CTS_SQL_MIN_LEN] = {0};
42         snprintf(query, sizeof(query), "DELETE FROM "CTS_TABLE_PHONELOG_STAT);
43         return ctsvc_query_exec(query);
44 }
45
46 int ctsvc_phone_log_reset_statistics_by_sim(int sim_slot_no)
47 {
48         char query[CTS_SQL_MIN_LEN] = {0};
49         int sim_info_id;
50
51         RETVM_IF(false == ctsvc_server_have_telephony_feature(), CONTACTS_ERROR_NOT_SUPPORTED, "Telephony feature disabled");
52
53         sim_info_id = ctsvc_server_sim_get_info_id_by_sim_slot_no(sim_slot_no);
54         if (sim_info_id <= 0) {
55                 ERR("ctsvc_server_sim_get_info_id_by_sim_slot_no() Fail(%d)", sim_info_id);
56                 return CONTACTS_ERROR_NO_DATA;
57         }
58
59         snprintf(query, sizeof(query), "DELETE FROM "CTS_TABLE_PHONELOG_STAT
60                         " WHERE sim_id = %d", sim_info_id);
61         return ctsvc_query_exec(query);
62 }
63
64 int ctsvc_phone_log_delete(contacts_phone_log_delete_e op, ...)
65 {
66         int ret;
67         int extra_data1;
68         char query[CTS_SQL_MAX_LEN] = {0};
69         char *number = NULL;
70         va_list args;
71
72         switch (op) {
73         case CONTACTS_PHONE_LOG_DELETE_BY_ADDRESS:
74                 va_start(args, op);
75                 number = va_arg(args, char *);
76                 va_end(args);
77                 RETV_IF(NULL == number, CONTACTS_ERROR_INVALID_PARAMETER);
78                 snprintf(query, sizeof(query), "DELETE FROM "CTS_TABLE_PHONELOGS" WHERE number = '%s'", number);
79                 break;
80         case CONTACTS_PHONE_LOG_DELETE_BY_MESSAGE_EXTRA_DATA1:
81                 va_start(args, op);
82                 extra_data1 = va_arg(args, int);
83                 va_end(args);
84                 snprintf(query, sizeof(query),
85                                 "DELETE FROM "CTS_TABLE_PHONELOGS" "
86                                 "WHERE data1 = %d AND %d <= log_type AND log_type <= %d",
87                                 extra_data1, CONTACTS_PLOG_TYPE_MMS_INCOMING, CONTACTS_PLOG_TYPE_MMS_BLOCKED);
88                 break;
89         case CONTACTS_PHONE_LOG_DELETE_BY_EMAIL_EXTRA_DATA1:
90                 va_start(args, op);
91                 extra_data1 = va_arg(args, int);
92                 va_end(args);
93                 snprintf(query, sizeof(query),
94                                 "DELETE FROM "CTS_TABLE_PHONELOGS" "
95                                 "WHERE data1 = %d AND %d <= log_type AND log_type <= %d",
96                                 extra_data1, CONTACTS_PLOG_TYPE_EMAIL_RECEIVED, CONTACTS_PLOG_TYPE_EMAIL_SENT);
97                 break;
98         default:
99                 ERR("the operation is not proper (op : %d)", op);
100                 return CONTACTS_ERROR_INVALID_PARAMETER;
101         }
102         ret = ctsvc_begin_trans();
103         RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
104
105         ret = ctsvc_query_exec(query);
106         if (CONTACTS_ERROR_NONE != ret) {
107                 ERR("ctsvc_query_exec() Fail(%d)", ret);
108                 ctsvc_end_trans(false);
109                 return ret;
110         }
111         ctsvc_set_phonelog_noti();
112         ret = ctsvc_end_trans(true);
113         return ret;
114 }
115
116 void ctsvc_db_phone_log_delete_callback(sqlite3_context  *context,
117                 int argc, sqlite3_value **argv)
118 {
119 #ifdef _CONTACTS_IPC_SERVER
120         int phone_log_id;
121
122         if (argc < 1) {
123                 sqlite3_result_null(context);
124                 return;
125         }
126
127         phone_log_id = sqlite3_value_int(argv[0]);
128         ctsvc_change_subject_add_changed_phone_log_id(CONTACTS_CHANGE_DELETED, phone_log_id);
129
130         sqlite3_result_null(context);
131         return;
132 #endif
133 }
134
135 static int __ctsvc_db_phone_log_find_person_id(char *number, char *normal_num,
136                         char *minmatch, int person_id, int *find_number_type)
137 {
138         int ret;
139         int find_person_id = -1;
140         char query[CTS_SQL_MAX_LEN] = {0};
141         GSList *bind_text = NULL;
142         GSList *cursor = NULL;
143         int i = 0;
144
145         *find_number_type = -1;
146         if (normal_num) {
147                 ret = snprintf(query, sizeof(query),
148                                 "SELECT person_id, data1 FROM "CTS_TABLE_CONTACTS", "CTS_TABLE_DATA" "
149                                 "ON "CTS_TABLE_CONTACTS".contact_id = "CTS_TABLE_DATA".contact_id "
150                                 "AND datatype = %d AND is_my_profile = 0 AND deleted = 0 "
151                                 "WHERE data4 = ? AND _NUMBER_COMPARE_(data5, ?, NULL, NULL)",
152                                 CONTACTS_DATA_TYPE_NUMBER);
153                 bind_text = g_slist_append(bind_text, strdup(minmatch));
154                 bind_text = g_slist_append(bind_text, strdup(normal_num));
155         }
156
157         if (*query) {
158                 /* several person can have same number */
159                 cts_stmt stmt = NULL;
160                 int id;
161                 int number_type = -1;
162
163                 ret = ctsvc_query_prepare(query, &stmt);
164                 if (stmt == NULL) {
165                         ERR("ctsvc_query_prepare fail(%d)", ret);
166                         if (bind_text) {
167                                 for (cursor = bind_text; cursor; cursor = cursor->next)
168                                         free(cursor->data);
169                                 g_slist_free(bind_text);
170                         }
171                         return CONTACTS_ERROR_DB;
172                 }
173
174                 if (bind_text) {
175                         for (cursor = bind_text, i = 1; cursor; cursor = cursor->next, i++) {
176                                 const char *text = cursor->data;
177                                 if (text && *text)
178                                         ctsvc_stmt_bind_text(stmt, i, text);
179                         }
180                 }
181
182                 while ((ret = ctsvc_stmt_step(stmt))) {
183                         id = ctsvc_stmt_get_int(stmt, 0);
184                         number_type = ctsvc_stmt_get_int(stmt, 1);
185                         if (find_person_id <= 0 && 0 < id) {
186                                 find_person_id = id;   /* find first match person_id */
187                                 *find_number_type = number_type;
188                                 if (person_id <= 0)
189                                         break;
190                         }
191
192                         if (id == person_id) {
193                                 find_person_id = person_id;
194                                 *find_number_type = number_type;
195                                 break;
196                         }
197                 }
198                 ctsvc_stmt_finalize(stmt);
199         }
200
201         if (bind_text) {
202                 for (cursor = bind_text; cursor; cursor = cursor->next)
203                         free(cursor->data);
204                 g_slist_free(bind_text);
205         }
206
207         return find_person_id;
208 }
209
210 int ctsvc_db_phone_log_update_person_id(const char *number, int old_person_id,
211                 int candidate_person_id, bool person_link, int *found_person_id)
212 {
213         CTS_FN_CALL;
214         int ret;
215         int len = 0;
216         char query[CTS_SQL_MAX_LEN] = {0};
217         cts_stmt get_log = NULL;
218         cts_stmt update_log = NULL;
219         GSList *bind_text = NULL;
220         GSList *cursor = NULL;
221         int i = 0;
222         bool need_noti = false;
223
224         RETVM_IF(old_person_id <= 0 && NULL == number, CONTACTS_ERROR_INVALID_PARAMETER,
225                         "old person_id (%d), number is NULL", old_person_id);
226
227         len = snprintf(query, sizeof(query),
228                         "SELECT id, number, normal_num, minmatch FROM "CTS_TABLE_PHONELOGS" "
229                         "WHERE log_type <= %d ",
230                         CONTACTS_PLOG_TYPE_EMAIL_RECEIVED);
231
232         if (number && *number) {
233                 char clean_num[strlen(number)+1];
234                 len += snprintf(query+len, sizeof(query)-len, "AND ((number = ?) ");
235                 bind_text = g_slist_append(bind_text, strdup(number));
236
237                 ret = ctsvc_clean_number(number, clean_num, sizeof(clean_num), true);
238                 if (0 < ret) {
239                         char normal_num[sizeof(clean_num) + 20];
240                         ret = ctsvc_normalize_number(clean_num, normal_num, sizeof(normal_num), true);
241                         if (0 < ret) {
242                                 char minmatch[sizeof(normal_num)+1];
243                                 ret = ctsvc_get_minmatch_number(normal_num, minmatch, sizeof(minmatch),
244                                                 ctsvc_get_phonenumber_min_match_digit());
245                                 if (CONTACTS_ERROR_NONE == ret) {
246                                         len += snprintf(query+len, sizeof(query)-len,
247                                                         "OR (minmatch = ? AND _NUMBER_COMPARE_(normal_num, ?, NULL, NULL))) ");
248                                         bind_text = g_slist_append(bind_text, strdup(minmatch));
249                                         bind_text = g_slist_append(bind_text, strdup(normal_num));
250                                 } else {
251                                         len += snprintf(query+len, sizeof(query)-len, ") ");
252                                 }
253                         } else {
254                                 len += snprintf(query+len, sizeof(query)-len, ") ");
255                         }
256                 } else {
257                         len += snprintf(query+len, sizeof(query)-len, ") ");
258                 }
259         }
260
261         if (0 < old_person_id)
262                 len += snprintf(query+len, sizeof(query)-len, "AND person_id = %d ", old_person_id);
263         else
264                 len += snprintf(query+len, sizeof(query)-len, "AND person_id IS NULL ");
265
266         ret = ctsvc_query_prepare(query, &get_log);
267         if (get_log == NULL) {
268                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
269                 if (bind_text) {
270                         for (cursor = bind_text; cursor; cursor = cursor->next)
271                                 free(cursor->data);
272                         g_slist_free(bind_text);
273                 }
274                 return CONTACTS_ERROR_DB;
275         }
276
277         if (bind_text) {
278                 for (cursor = bind_text, i = 1; cursor; cursor = cursor->next, i++) {
279                         const char *text = cursor->data;
280                         if (text && *text)
281                                 ctsvc_stmt_bind_text(get_log, i, text);
282                 }
283         }
284
285         snprintf(query, sizeof(query),
286                         "UPDATE "CTS_TABLE_PHONELOGS" SET person_id=?, number_type = ? WHERE id = ?");
287         ret = ctsvc_query_prepare(query, &update_log);
288         if (update_log == NULL) {
289                 ERR("ctsvc_query_prepare() Fail(%d)", ret);
290                 ctsvc_stmt_finalize(get_log);
291
292                 if (bind_text) {
293                         for (cursor = bind_text; cursor; cursor = cursor->next)
294                                 free(cursor->data);
295                         g_slist_free(bind_text);
296                 }
297                 return CONTACTS_ERROR_DB;
298         }
299
300         while ((ret = ctsvc_stmt_step(get_log))) {
301                 int phonelog_id;
302                 int new_person_id = -1;
303                 int temp_id;
304                 int number_type = -1;
305                 char *address;
306                 char *normal_address;
307                 char *minmatch_address;
308
309                 phonelog_id = ctsvc_stmt_get_int(get_log, 0);
310                 address = ctsvc_stmt_get_text(get_log, 1);
311                 normal_address = ctsvc_stmt_get_text(get_log, 2);
312                 minmatch_address = ctsvc_stmt_get_text(get_log, 3);
313
314                 /* CASE : number is inserted (contact insert/update) => update person_id of phone logs from NULL */
315                 if (number && old_person_id <= 0 && 0 < candidate_person_id) {
316                         __ctsvc_db_phone_log_find_person_id(address, normal_address,
317                                         minmatch_address, candidate_person_id, &number_type);
318                         new_person_id = candidate_person_id;
319                 } else if (number && old_person_id <= 0) {
320                         /* CASE : phonelog insert without person_id */
321                         /* address == number */
322                         new_person_id = __ctsvc_db_phone_log_find_person_id(address, normal_address,
323                                         minmatch_address, -1, &number_type);
324                         if (new_person_id <= 0)
325                                 continue;
326
327                         if (found_person_id)
328                                 *found_person_id = new_person_id;
329                 } else if (number && 0 < old_person_id) {
330                         /* CASE : number update/delete (contact update/delete) => find new_person_id by address */
331                         /* CASE : phonelog insert with person_id */
332                         /* address == number */
333                         /* although new_person_id and old_person_id are same, update phonelog for setting number_type */
334                         new_person_id = __ctsvc_db_phone_log_find_person_id(address, normal_address,
335                                         minmatch_address, old_person_id, &number_type);
336                 } else if (NULL == number && 0 < old_person_id && 0 < candidate_person_id && person_link) {
337                         /* CASE : person link => deleted person_id -> new person_id (base_person_id) */
338                         new_person_id = candidate_person_id;
339                 } else if (NULL == number && 0 < old_person_id && 0 < candidate_person_id) {
340                         /* CASE : person unlink => check person_id of the address, */
341                         /* if person_id is not old_person_id then change person_id to new_person_id */
342                         temp_id = __ctsvc_db_phone_log_find_person_id(address, normal_address,
343                                         minmatch_address, candidate_person_id, &number_type);
344                         if (0 < temp_id && temp_id == old_person_id)
345                                 continue;
346                         else if (0 < temp_id && temp_id != old_person_id)
347                                 new_person_id = temp_id;
348                 } else if (NULL == number && 0 < old_person_id) {
349                         /* CASE : person delete => find new_person_id by address */
350                         new_person_id = __ctsvc_db_phone_log_find_person_id(address, normal_address, minmatch_address, candidate_person_id, &number_type);
351                 }
352                 /* Already check this case as above : RETVM_IF(old_person_id <= 0 && NULL == number, ... */
353                 /*
354                  * else
355                  *  continue;
356                  */
357
358                 if (!need_noti)
359                         need_noti = true;
360
361                 if (0 < new_person_id)
362                         ctsvc_stmt_bind_int(update_log, 1, new_person_id);
363                 if (0 <= number_type)
364                         ctsvc_stmt_bind_int(update_log, 2, number_type);
365                 ctsvc_stmt_bind_int(update_log, 3, phonelog_id);
366                 ctsvc_stmt_step(update_log);
367                 ctsvc_stmt_reset(update_log);
368         }
369         ctsvc_stmt_finalize(get_log);
370         ctsvc_stmt_finalize(update_log);
371
372         if (need_noti)
373                 ctsvc_set_phonelog_noti();
374
375         if (bind_text) {
376                 for (cursor = bind_text; cursor; cursor = cursor->next)
377                         free(cursor->data);
378                 g_slist_free(bind_text);
379         }
380
381         return CONTACTS_ERROR_NONE;
382 }
383