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