Fixed the build error for gcc-14
[platform/core/pim/contacts-service.git] / client / ctsvc_client_noti.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 <stdio.h>
21 #include <unistd.h>
22 #include <pims-ipc.h>
23 #include <pims-ipc-svc.h>
24 #include <pims-ipc-data.h>
25
26 #include "contacts.h"
27 #include "ctsvc_internal.h"
28 #include "ctsvc_ipc_define.h"
29 #include "ctsvc_ipc_marshal.h"
30 #include "ctsvc_mutex.h"
31 #include "ctsvc_client_ipc.h"
32 #include "ctsvc_client_setting.h"
33 #include "contacts_extension.h"
34 #include "ctsvc_client_utils.h"
35
36 typedef struct {
37         contacts_db_change_cb_with_info cb;
38         void *user_data;
39 } db_callback_info_s;
40
41 typedef struct {
42         char *view_uri;
43         GSList *callbacks;
44 } subscribe_info_s;
45
46 static int __ipc_pubsub_ref = 0;
47 static pims_ipc_h __ipc = NULL;
48 static GSList *__db_change_subscribe_list = NULL;
49
50 static void _cnoti_subscribe_cb(pims_ipc_h ipc, pims_ipc_data_h data,
51                 void *user_data)
52 {
53         int ret;
54         char *str = NULL;
55         subscribe_info_s *info = user_data;
56
57         if (data) {
58                 ret = ctsvc_ipc_unmarshal_string(data, &str);
59                 WARN_IF(CONTACTS_ERROR_NONE != ret, "ctsvc_ipc_unmarshal_string() Fail(%d)", ret);
60         }
61
62         if (NULL == str) {
63                 /* LCOV_EXCL_START */
64                 ERR("There is no changed data");
65                 free(str);
66                 return;
67                 /* LCOV_EXCL_STOP */
68         }
69
70         if (info) {
71                 GSList *l;
72                 for (l = info->callbacks; l; l = l->next) {
73                         db_callback_info_s *cb_info = l->data;
74                         if (cb_info->cb)
75                                 cb_info->cb(info->view_uri, str, cb_info->user_data);
76                 }
77         }
78         free(str);
79 }
80
81 /* LCOV_EXCL_START */
82 int _cnoti_recover_for_change_subscription()
83 {
84         GSList *it = NULL;
85         subscribe_info_s *info = NULL;
86
87         for (it = __db_change_subscribe_list; it; it = it->next) {
88                 if (NULL == it->data)
89                         continue;
90
91                 info = it->data;
92                 if (info->view_uri) {
93                         if (pims_ipc_subscribe(__ipc, CTSVC_IPC_SUBSCRIBE_MODULE, info->view_uri,
94                                                 _cnoti_subscribe_cb, (void*)info) != 0) {
95                                 ERR("pims_ipc_subscribe() Fail");
96                                 return CONTACTS_ERROR_IPC;
97                         }
98                 }
99         }
100
101         return CONTACTS_ERROR_NONE;
102 }
103 /* LCOV_EXCL_STOP */
104
105
106 /* This API should be called in CTS_MUTEX_PIMS_IPC_PUBSUB mutex */
107 pims_ipc_h ctsvc_ipc_get_handle_for_change_subsciption()
108 {
109         return __ipc;
110 }
111
112 int ctsvc_ipc_create_for_change_subscription()
113 {
114         ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_PUBSUB);
115
116         if (0 < __ipc_pubsub_ref) {
117                 __ipc_pubsub_ref++;
118                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
119                 return CONTACTS_ERROR_NONE;
120         }
121
122         if (NULL == __ipc) {
123                 char sock_file[CTSVC_PATH_MAX_LEN] = {0};
124                 uid_t uid = getuid();
125
126                 if (ctsvc_client_is_in_system_session()) {
127                         if (CONTACTS_ERROR_NONE != ctsvc_client_get_active_uid(&uid))
128                                 return CONTACTS_ERROR_SYSTEM;
129                 }
130
131                 snprintf(sock_file, sizeof(sock_file), CTSVC_SOCK_PATH"/.%s_for_subscribe",
132                                 uid, CTSVC_IPC_SERVICE);
133                 __ipc = pims_ipc_create_for_subscribe(sock_file);
134                 if (NULL == __ipc) {
135                         /* LCOV_EXCL_START */
136                         ERR("pims_ipc_create_for_subscribe() Fail");
137                         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
138                         return CONTACTS_ERROR_IPC;
139                         /* LCOV_EXCL_STOP */
140                 }
141         }
142         __ipc_pubsub_ref++;
143         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
144         return CONTACTS_ERROR_NONE;
145 }
146
147 /* LCOV_EXCL_START */
148 int ctsvc_ipc_recover_for_change_subscription()
149 {
150         int ret;
151         ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_PUBSUB);
152         if (__ipc_pubsub_ref <= 0) {
153                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
154                 return CONTACTS_ERROR_NONE;
155         }
156
157         pims_ipc_destroy_for_subscribe(__ipc);
158         char sock_file[CTSVC_PATH_MAX_LEN] = {0};
159         uid_t uid = getuid();
160
161         if (ctsvc_client_is_in_system_session()) {
162                 if (CONTACTS_ERROR_NONE != ctsvc_client_get_active_uid(&uid))
163                         return CONTACTS_ERROR_SYSTEM;
164         }
165
166         snprintf(sock_file, sizeof(sock_file), CTSVC_SOCK_PATH"/.%s_for_subscribe",
167                         uid, CTSVC_IPC_SERVICE);
168         __ipc = pims_ipc_create_for_subscribe(sock_file);
169         if (NULL == __ipc) {
170                 ERR("pims_ipc_create_for_subscribe() Fail");
171                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
172                 return CONTACTS_ERROR_IPC;
173         }
174         ret = ctsvc_setting_recover_for_change_subscription();
175         if (CONTACTS_ERROR_NONE != ret) {
176                 ERR("ctsvc_setting_recover_for_change_subscription() Fail(%d)", ret);
177                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
178                 return ret;
179         }
180         ret = _cnoti_recover_for_change_subscription();
181         if (CONTACTS_ERROR_NONE != ret) {
182                 ERR("__ctsvc_db_recover_changed_cb_with_info() Fail(%d)", ret);
183                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
184                 return ret;
185         }
186
187         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
188         return CONTACTS_ERROR_NONE;
189 }
190 /* LCOV_EXCL_STOP */
191
192 int ctsvc_ipc_destroy_for_change_subscription(bool is_disconnect)
193 {
194         ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_PUBSUB);
195         if (is_disconnect) {
196                 if (0 < __ipc_pubsub_ref) {
197                         pims_ipc_destroy_for_subscribe(__ipc);
198                         __ipc = NULL;
199                         __ipc_pubsub_ref = 0;
200                 }
201                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
202                 return CONTACTS_ERROR_NONE;
203         }
204
205         if (1 == __ipc_pubsub_ref) {
206                 pims_ipc_destroy_for_subscribe(__ipc);
207                 __ipc = NULL;
208         } else if (1 < __ipc_pubsub_ref) {
209                 DBG("ctsvc pubsub ipc ref count : %d", __ipc_pubsub_ref);
210         } else {
211                 /* LCOV_EXCL_START */
212                 DBG("System : please call connection APIs, connection count is (%d)",
213                                 __ipc_pubsub_ref);
214                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
215                 return CONTACTS_ERROR_INVALID_PARAMETER;
216                 /* LCOV_EXCL_STOP */
217         }
218
219         __ipc_pubsub_ref--;
220
221         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
222         return CONTACTS_ERROR_NONE;
223 }
224
225 EXPORT_API int contacts_db_add_changed_cb_with_info(const char *view_uri,
226                 contacts_db_change_cb_with_info cb, void *user_data)
227 {
228         CHECK_CONTACT_SUPPORTED(CONTACT_FEATURE);
229         GSList *it = NULL;
230         subscribe_info_s *info = NULL;
231         db_callback_info_s *cb_info;
232         bool result = false;
233         int ret;
234
235         RETV_IF(view_uri == NULL, CONTACTS_ERROR_INVALID_PARAMETER);
236         RETV_IF(cb == NULL, CONTACTS_ERROR_INVALID_PARAMETER);
237
238         if (STRING_EQUAL == strncmp(view_uri, CTSVC_VIEW_URI_PHONELOG, strlen(CTSVC_VIEW_URI_PHONELOG))) {
239                 ret = ctsvc_ipc_client_check_permission(CTSVC_PERMISSION_PHONELOG_READ, &result);
240                 if (CONTACTS_ERROR_NONE != ret) {
241                         /* LCOV_EXCL_START */
242                         ERR("ctsvc_ipc_client_check_permission() Fail(%d)", ret);
243                         return ret;
244                         /* LCOV_EXCL_STOP */
245                 }
246
247                 RETVM_IF(result == false, CONTACTS_ERROR_PERMISSION_DENIED,
248                                 "Permission denied (phonelog read)");
249         } else if (STRING_EQUAL == strncmp(view_uri, CTSVC_VIEW_URI_PERSON, strlen(CTSVC_VIEW_URI_PERSON))) {
250                 ret = ctsvc_ipc_client_check_permission(CTSVC_PERMISSION_CONTACT_READ, &result);
251                 if (CONTACTS_ERROR_NONE != ret) {
252                         /* LCOV_EXCL_START */
253                         ERR("ctsvc_ipc_client_check_permission() Fail(%d)", ret);
254                         return ret;
255                         /* LCOV_EXCL_STOP */
256                 }
257
258                 RETVM_IF(result == false, CONTACTS_ERROR_PERMISSION_DENIED,
259                                 "Permission denied (contact read)");
260         } else {
261                 /* LCOV_EXCL_START */
262                 ERR("We support this API for only %s and %s", CTSVC_VIEW_URI_PERSON,
263                                 CTSVC_VIEW_URI_PHONELOG);
264                 return CONTACTS_ERROR_INVALID_PARAMETER;
265                 /* LCOV_EXCL_STOP */
266         }
267
268         ret = ctsvc_ipc_create_for_change_subscription();
269         if (CONTACTS_ERROR_NONE != ret) {
270                 /* LCOV_EXCL_START */
271                 ERR("ctsvc_ipc_create_for_change_subscription() Fail(%d)", ret);
272                 return ret;
273                 /* LCOV_EXCL_STOP */
274         }
275
276         ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_PUBSUB);
277
278         for (it = __db_change_subscribe_list; it; it = it->next) {
279                 if (NULL == it->data) continue;
280
281                 info = it->data;
282                 if (STRING_EQUAL == strcmp(info->view_uri, view_uri))
283                         break;
284                 else
285                         info = NULL;
286         }
287
288         if (NULL == info) {
289                 info = calloc(1, sizeof(subscribe_info_s));
290                 if (NULL == info) {
291                         /* LCOV_EXCL_START */
292                         ERR("calloc() Fail");
293                         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
294                         return CONTACTS_ERROR_OUT_OF_MEMORY;
295                         /* LCOV_EXCL_STOP */
296                 }
297
298                 if (pims_ipc_subscribe(__ipc, CTSVC_IPC_SUBSCRIBE_MODULE, (char*)view_uri,
299                                         _cnoti_subscribe_cb, (void*)info) != 0) {
300                         /* LCOV_EXCL_START */
301                         ERR("pims_ipc_subscribe() Fail");
302                         free(info);
303                         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
304                         return CONTACTS_ERROR_IPC;
305                         /* LCOV_EXCL_STOP */
306                 }
307                 info->view_uri = strdup(view_uri);
308                 __db_change_subscribe_list = g_slist_append(__db_change_subscribe_list, info);
309         } else {
310                 GSList *l;
311                 for (l = info->callbacks; l; l = l->next) {
312                         db_callback_info_s *cb_info = l->data;
313                         if (cb_info->cb == cb && cb_info->user_data == user_data) {
314                                 /* LCOV_EXCL_START */
315                                 ERR("The same callback(%s) is already exist", view_uri);
316                                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
317                                 return CONTACTS_ERROR_INVALID_PARAMETER;
318                                 /* LCOV_EXCL_STOP */
319                         }
320                 }
321         }
322
323         cb_info = calloc(1, sizeof(db_callback_info_s));
324         if (NULL == cb_info) {
325                 /* LCOV_EXCL_START */
326                 ERR("calloc() Fail");
327                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
328                 return CONTACTS_ERROR_OUT_OF_MEMORY;
329                 /* LCOV_EXCL_STOP */
330         }
331         cb_info->user_data = user_data;
332         cb_info->cb = cb;
333         info->callbacks = g_slist_append(info->callbacks, cb_info);
334
335         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
336         return CONTACTS_ERROR_NONE;
337 }
338
339 EXPORT_API int contacts_db_remove_changed_cb_with_info(const char *view_uri,
340                 contacts_db_change_cb_with_info cb, void *user_data)
341 {
342         CHECK_CONTACT_SUPPORTED(CONTACT_FEATURE);
343         int ret;
344         GSList *it = NULL;
345         subscribe_info_s *info = NULL;
346
347         RETV_IF(view_uri == NULL, CONTACTS_ERROR_INVALID_PARAMETER);
348         RETV_IF(cb == NULL, CONTACTS_ERROR_INVALID_PARAMETER);
349
350         if (STRING_EQUAL != strcmp(view_uri, CTSVC_VIEW_URI_PHONELOG)
351                         && STRING_EQUAL != strcmp(view_uri, CTSVC_VIEW_URI_PERSON)) {
352                 /* LCOV_EXCL_START */
353                 ERR("We support this API for only %s and %s", CTSVC_VIEW_URI_PERSON,
354                                 CTSVC_VIEW_URI_PHONELOG);
355                 return CONTACTS_ERROR_INVALID_PARAMETER;
356                 /* LCOV_EXCL_STOP */
357         }
358
359         ret = ctsvc_ipc_destroy_for_change_subscription(false);
360         if (CONTACTS_ERROR_NONE != ret) {
361                 /* LCOV_EXCL_START */
362                 ERR("ctsvc_ipc_destroy_for_change_subscription() Fail(%d)", ret);
363                 return ret;
364                 /* LCOV_EXCL_STOP */
365         }
366
367         ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_PUBSUB);
368
369         for (it = __db_change_subscribe_list; it; it = it->next) {
370                 if (NULL == it->data)
371                         continue;
372
373                 info = it->data;
374                 if (STRING_EQUAL == strcmp(info->view_uri, view_uri))
375                         break;
376                 else
377                         info = NULL;
378         }
379
380         if (info) {
381                 GSList *l;
382                 for (l = info->callbacks; l; l = l->next) {
383                         db_callback_info_s *cb_info = l->data;
384                         if (cb == cb_info->cb && user_data == cb_info->user_data) {
385                                 info->callbacks = g_slist_remove(info->callbacks, cb_info);
386                                 free(cb_info);
387                                 break;
388                         }
389                 }
390                 if (g_slist_length(info->callbacks) == 0) {
391                         pims_ipc_unsubscribe(__ipc, CTSVC_IPC_SUBSCRIBE_MODULE, info->view_uri);
392                         __db_change_subscribe_list = g_slist_remove(__db_change_subscribe_list, info);
393                         free(info->view_uri);
394                         free(info);
395                 }
396         }
397
398         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
399         return CONTACTS_ERROR_NONE;
400 }