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