ctsvc_client_handle_remove in CTS_MUTEX_CONNECTION during disconnect_on_thread
[platform/core/pim/contacts-service.git] / client / ctsvc_client_noti.c
1 /*
2  * Contacts Service
3  *
4  * Copyright (c) 2010 - 2012 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
35 typedef struct
36 {
37         contacts_db_change_cb_with_info cb;
38         void *user_data;
39 }db_callback_info_s;
40
41 typedef struct
42 {
43         char *view_uri;
44         GSList *callbacks;
45 }subscribe_info_s;
46
47 static int __ipc_pubsub_ref = 0;
48 static pims_ipc_h __ipc = NULL;
49 static GSList *__db_change_subscribe_list = NULL;
50
51 static void __ctsvc_db_subscriber_callback(pims_ipc_h ipc, pims_ipc_data_h data, 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                 CTS_ERR("There is no changed data");
64                 goto DATA_FREE;
65         }
66
67         if (info) {
68                 GSList *l;
69                 for (l = info->callbacks;l;l=l->next) {
70                         db_callback_info_s *cb_info = l->data;
71                         if (cb_info->cb) {
72                                 cb_info->cb(info->view_uri, str, cb_info->user_data);
73                         }
74                 }
75         }
76 DATA_FREE:
77         free(str);
78 }
79
80 int __ctsvc_db_recover_for_change_subscription()
81 {
82         GSList *it = NULL;
83         subscribe_info_s *info = NULL;
84
85         for (it=__db_change_subscribe_list;it;it=it->next) {
86                 if (NULL == it->data) continue;
87
88                 info = it->data;
89                 if (info->view_uri) {
90                         if (pims_ipc_subscribe(__ipc, CTSVC_IPC_SUBSCRIBE_MODULE, info->view_uri,
91                                                 __ctsvc_db_subscriber_callback, (void*)info) != 0) {
92                                 CTS_ERR("pims_ipc_subscribe() Fail");
93                                 return CONTACTS_ERROR_IPC;
94                         }
95                 }
96         }
97
98         return CONTACTS_ERROR_NONE;
99 }
100
101
102 /* This API should be called in CTS_MUTEX_PIMS_IPC_PUBSUB mutex */
103 pims_ipc_h ctsvc_ipc_get_handle_for_change_subsciption()
104 {
105         return __ipc;
106 }
107
108 int ctsvc_ipc_create_for_change_subscription()
109 {
110         ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_PUBSUB);
111
112         if (0 < __ipc_pubsub_ref) {
113                 __ipc_pubsub_ref++;
114                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
115                 return CONTACTS_ERROR_NONE;
116         }
117
118         if (NULL == __ipc) {
119                 char sock_file[CTSVC_PATH_MAX_LEN] = {0};
120                 snprintf(sock_file, sizeof(sock_file), CTSVC_SOCK_PATH"/.%s_for_subscribe", getuid(), CTSVC_IPC_SERVICE);
121                 __ipc = pims_ipc_create_for_subscribe(sock_file);
122                 if (NULL == __ipc) {
123                         CTS_ERR("pims_ipc_create_for_subscribe() Fail");
124                         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
125                         return CONTACTS_ERROR_IPC;
126                 }
127         }
128         __ipc_pubsub_ref++;
129         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
130         return CONTACTS_ERROR_NONE;
131 }
132
133 int ctsvc_ipc_recover_for_change_subscription()
134 {
135         int ret;
136         ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_PUBSUB);
137         if (__ipc_pubsub_ref <= 0) {
138                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
139                 return CONTACTS_ERROR_NONE;
140         }
141
142         pims_ipc_destroy_for_subscribe(__ipc);
143         __ipc = pims_ipc_create_for_subscribe(CTSVC_IPC_SOCKET_PATH_FOR_CHANGE_SUBSCRIPTION);
144         if (NULL == __ipc) {
145                 CTS_ERR("pims_ipc_create_for_subscribe() Fail");
146                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
147                 return CONTACTS_ERROR_IPC;
148         }
149         ret = ctsvc_setting_recover_for_change_subscription();
150         if (CONTACTS_ERROR_NONE != ret) {
151                 CTS_ERR("ctsvc_setting_recover_for_change_subscription() Fail(%d)", ret);
152                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
153                 return ret;
154         }
155         ret = __ctsvc_db_recover_for_change_subscription();
156         if (CONTACTS_ERROR_NONE != ret) {
157                 CTS_ERR("__ctsvc_db_recover_changed_cb_with_info() Fail(%d)", ret);
158                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
159                 return ret;
160         }
161
162         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
163         return CONTACTS_ERROR_NONE;
164 }
165
166 int ctsvc_ipc_destroy_for_change_subscription()
167 {
168         ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_PUBSUB);
169
170         if (1 == __ipc_pubsub_ref) {
171                 pims_ipc_destroy_for_subscribe(__ipc);
172                 __ipc = NULL;
173         }
174         else if (1 < __ipc_pubsub_ref) {
175                 CTS_DBG("ctsvc pubsub ipc ref count : %d", __ipc_pubsub_ref);
176         }
177         else {
178                 CTS_DBG("System : please call connection APIs, connection count is (%d)", __ipc_pubsub_ref);
179                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
180                 return CONTACTS_ERROR_INVALID_PARAMETER;
181         }
182
183         __ipc_pubsub_ref--;
184
185         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
186         return CONTACTS_ERROR_NONE;
187 }
188
189 API int contacts_db_add_changed_cb_with_info(const char* view_uri,
190                 contacts_db_change_cb_with_info cb, void* user_data)
191 {
192         GSList *it = NULL;
193         subscribe_info_s *info = NULL;
194         db_callback_info_s *cb_info;
195         bool result = false;
196         int ret;
197
198         RETVM_IF(view_uri == NULL, CONTACTS_ERROR_INVALID_PARAMETER, "view_uri is NULL");
199         RETVM_IF(cb == NULL, CONTACTS_ERROR_INVALID_PARAMETER, "cb is NULL");
200
201         if (STRING_EQUAL == strncmp(view_uri, CTSVC_VIEW_URI_PHONELOG, strlen(CTSVC_VIEW_URI_PHONELOG))) {
202                 ret = ctsvc_ipc_client_check_permission(CTSVC_PERMISSION_PHONELOG_READ, &result);
203                 RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "ctsvc_ipc_client_check_permission() Fail(%d)", ret);
204                 RETVM_IF(result == false, CONTACTS_ERROR_PERMISSION_DENIED, "Permission denied (phonelog read)");
205         }
206         else if (STRING_EQUAL == strncmp(view_uri, CTSVC_VIEW_URI_PERSON, strlen(CTSVC_VIEW_URI_PERSON))) {
207                 ret = ctsvc_ipc_client_check_permission(CTSVC_PERMISSION_CONTACT_READ, &result);
208                 RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "ctsvc_ipc_client_check_permission() Fail(%d)", ret);
209                 RETVM_IF(result == false, CONTACTS_ERROR_PERMISSION_DENIED, "Permission denied (contact read)");
210         }
211         else {
212                 CTS_ERR("We support this API for only %s and %s", CTSVC_VIEW_URI_PERSON, CTSVC_VIEW_URI_PHONELOG);
213                 return CONTACTS_ERROR_INVALID_PARAMETER;
214         }
215
216         ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_PUBSUB);
217
218         for (it=__db_change_subscribe_list;it;it=it->next) {
219                 if (NULL == it->data) continue;
220
221                 info = it->data;
222                 if (STRING_EQUAL == strcmp(info->view_uri, view_uri))
223                         break;
224                 else
225                         info = NULL;
226         }
227
228         if (NULL == info) {
229                 info = calloc(1, sizeof(subscribe_info_s));
230                 if (NULL == info) {
231                         CTS_ERR("calloc() Fail");
232                         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
233                         return CONTACTS_ERROR_OUT_OF_MEMORY;
234                 }
235
236                 if (pims_ipc_subscribe(__ipc, CTSVC_IPC_SUBSCRIBE_MODULE, (char*)view_uri,
237                                         __ctsvc_db_subscriber_callback, (void*)info) != 0) {
238                         CTS_ERR("pims_ipc_subscribe() Fail");
239                         free(info);
240                         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
241                         return CONTACTS_ERROR_IPC;
242                 }
243                 info->view_uri = strdup(view_uri);
244                 __db_change_subscribe_list = g_slist_append(__db_change_subscribe_list, info);
245         }
246         else {
247                 GSList *l;
248                 for (l = info->callbacks;l;l=l->next) {
249                         db_callback_info_s *cb_info = l->data;
250                         if (cb_info->cb == cb && cb_info->user_data == user_data) {
251                                 CTS_ERR("The same callback(%s) is already exist", view_uri);
252                                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
253                                 return CONTACTS_ERROR_INVALID_PARAMETER;
254                         }
255                 }
256         }
257
258         cb_info = calloc(1, sizeof(db_callback_info_s));
259         if (NULL == cb_info) {
260                 CTS_ERR("calloc() Fail");
261                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
262                 return CONTACTS_ERROR_OUT_OF_MEMORY;
263         }
264         cb_info->user_data = user_data;
265         cb_info->cb = cb;
266         info->callbacks = g_slist_append(info->callbacks, cb_info);
267
268         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
269         return CONTACTS_ERROR_NONE;
270 }
271
272 API int contacts_db_remove_changed_cb_with_info(const char* view_uri,
273                 contacts_db_change_cb_with_info cb, void* user_data)
274 {
275         GSList *it = NULL;
276         subscribe_info_s *info = NULL;
277
278         RETVM_IF(view_uri == NULL, CONTACTS_ERROR_INVALID_PARAMETER, "view_uri is NULL");
279         RETVM_IF(cb == NULL, CONTACTS_ERROR_INVALID_PARAMETER, "cb is NULL");
280
281         if (STRING_EQUAL != strcmp(view_uri, CTSVC_VIEW_URI_PHONELOG) &&
282                         STRING_EQUAL != strcmp(view_uri, CTSVC_VIEW_URI_PERSON)) {
283                 CTS_ERR("We support this API for only %s and %s", CTSVC_VIEW_URI_PERSON, CTSVC_VIEW_URI_PHONELOG);
284                 return CONTACTS_ERROR_INVALID_PARAMETER;
285         }
286
287         ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_PUBSUB);
288
289         for (it=__db_change_subscribe_list;it;it=it->next) {
290                 if (NULL == it->data) continue;
291
292                 info = it->data;
293                 if (STRING_EQUAL == strcmp(info->view_uri, view_uri))
294                         break;
295                 else
296                         info = NULL;
297         }
298
299         if (info) {
300                 GSList *l;
301                 for (l = info->callbacks;l;l=l->next) {
302                         db_callback_info_s *cb_info = l->data;
303                         if (cb == cb_info->cb && user_data == cb_info->user_data) {
304                                 info->callbacks = g_slist_remove(info->callbacks, cb_info);
305                                 free(cb_info);
306                                 break;
307                         }
308                 }
309                 if (g_slist_length(info->callbacks) == 0) {
310                         pims_ipc_unsubscribe(__ipc, CTSVC_IPC_SUBSCRIBE_MODULE, info->view_uri);
311                         __db_change_subscribe_list = g_slist_remove(__db_change_subscribe_list, info);
312                         free(info->view_uri);
313                         free(info);
314                 }
315         }
316
317         ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
318         return CONTACTS_ERROR_NONE;
319 }