Fix the issue that changed callback is not working
[platform/core/appfw/notification-service.git] / notification_service.c
1 /*
2  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17 #include <stdio.h>
18 #include <Eina.h>
19 #include <packet.h>
20 #include <notification_ipc.h>
21 #include <notification_noti.h>
22 #include <notification_error.h>
23
24 #include "service_common.h"
25
26 #ifndef NOTIFICATION_ADDR
27 #define NOTIFICATION_ADDR "/tmp/.notification.service"
28 #endif
29
30 #ifndef NOTIFICATION_DEL_PACKET_UNIT
31 #define NOTIFICATION_DEL_PACKET_UNIT 10
32 #endif
33
34 static struct info {
35     Eina_List *context_list;
36     struct service_context *svc_ctx;
37 } s_info = {
38         .context_list = NULL, /*!< \WARN: This is only used for SERVICE THREAD */
39         .svc_ctx = NULL, /*!< \WARN: This is only used for MAIN THREAD */
40 };
41
42 struct context {
43         struct tcb *tcb;
44         double seq;
45 };
46
47 struct noti_service {
48         const char *cmd;
49         void (*handler)(struct tcb *tcb, struct packet *packet, void *data);
50 };
51
52 /*!
53  * FUNCTIONS to handle notifcation
54  */
55 static inline int get_priv_id(int num_deleted, int *list_deleted, int index) {
56         if (index < num_deleted) {
57                 return *(list_deleted + index);
58         } else {
59                 return -1;
60         }
61 }
62
63 static inline char *get_string(char *string)
64 {
65         if (string == NULL) {
66                 return NULL;
67         }
68         if (string[0] == '\0') {
69                 return NULL;
70         }
71
72         return string;
73 }
74
75 static inline struct packet *create_packet_from_deleted_list(int op_num, int *list, int start_index) {
76         return packet_create(
77                 "del_noti_multiple",
78                 "iiiiiiiiiii",
79                 ((op_num - start_index) > NOTIFICATION_DEL_PACKET_UNIT) ? NOTIFICATION_DEL_PACKET_UNIT : op_num - start_index,
80                 get_priv_id(op_num, list, start_index),
81                 get_priv_id(op_num, list, start_index + 1),
82                 get_priv_id(op_num, list, start_index + 2),
83                 get_priv_id(op_num, list, start_index + 3),
84                 get_priv_id(op_num, list, start_index + 4),
85                 get_priv_id(op_num, list, start_index + 5),
86                 get_priv_id(op_num, list, start_index + 6),
87                 get_priv_id(op_num, list, start_index + 7),
88                 get_priv_id(op_num, list, start_index + 8),
89                 get_priv_id(op_num, list, start_index + 9)
90                 );
91 }
92
93 /*!
94  * SERVICE HANDLER
95  */
96 static void _handler_insert(struct tcb *tcb, struct packet *packet, void *data)
97 {
98         int ret = 0;
99         int priv_id = 0;
100         struct packet *packet_reply = NULL;
101         struct packet *packet_service = NULL;
102         notification_h noti = NULL;
103
104         noti = notification_create(NOTIFICATION_TYPE_NOTI);
105         if (noti != NULL) {
106                 if (notification_ipc_make_noti_from_packet(noti, packet) == NOTIFICATION_ERROR_NONE) {
107                         ret = notification_noti_insert(noti);
108                         if (ret != NOTIFICATION_ERROR_NONE) {
109                                 notification_free(noti);
110                                 return ;
111                         }
112
113                         notification_get_id(noti, NULL, &priv_id);
114                         packet_reply = packet_create_reply(packet, "ii", ret, priv_id);
115                         if (packet_reply) {
116                                 service_common_unicast_packet(tcb, packet_reply);
117                                 packet_destroy(packet_reply);
118                         }
119
120                         packet_service = notification_ipc_make_packet_from_noti(noti, "add_noti", 2);
121                         if (packet_service != NULL) {
122                                 service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE);
123                                 packet_destroy(packet_service);
124                         }
125                 }
126                 notification_free(noti);
127         }
128 }
129
130 static void _handler_update(struct tcb *tcb, struct packet *packet, void *data)
131 {
132         int ret = 0;
133         int priv_id = 0;
134         struct packet *packet_reply = NULL;
135         struct packet *packet_service = NULL;
136         notification_h noti = NULL;
137
138         noti = notification_create(NOTIFICATION_TYPE_NOTI);
139         if (noti != NULL) {
140                 if (notification_ipc_make_noti_from_packet(noti, packet) == NOTIFICATION_ERROR_NONE) {
141                         ret = notification_noti_update(noti);
142                         if (ret != NOTIFICATION_ERROR_NONE) {
143                                 notification_free(noti);
144                                 return ;
145                         }
146
147                         notification_get_id(noti, NULL, &priv_id);
148                         packet_reply = packet_create_reply(packet, "ii", ret, priv_id);
149                         if (packet_reply) {
150                                 service_common_unicast_packet(tcb, packet_reply);
151                                 packet_destroy(packet_reply);
152                         }
153
154                         packet_service = notification_ipc_make_packet_from_noti(noti, "update_noti", 2);
155                         if (packet_service != NULL) {
156                                 service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE);
157                                 packet_destroy(packet_service);
158                         }
159                 }
160                 notification_free(noti);
161         }
162 }
163
164 static void _handler_refresh(struct tcb *tcb, struct packet *packet, void *data)
165 {
166         int ret = NOTIFICATION_ERROR_NONE;
167         struct packet *packet_reply = NULL;
168
169         packet_reply = packet_create_reply(packet, "i", ret);
170         if (packet_reply) {
171                 service_common_unicast_packet(tcb, packet_reply);
172                 packet_destroy(packet_reply);
173         }
174
175         service_common_multicast_packet(tcb, packet, TCB_CLIENT_TYPE_SERVICE);
176 }
177
178 static void _handler_delete_single(struct tcb *tcb, struct packet *packet, void *data)
179 {
180         int ret = 0;
181         int priv_id = 0;
182         struct packet *packet_reply = NULL;
183         struct packet *packet_service = NULL;
184         char *pkgname = NULL;
185
186         if (packet_get(packet, "si", &pkgname, &priv_id) == 2) {
187                 pkgname = get_string(pkgname);
188
189                 ret = notification_noti_delete_by_priv_id(pkgname, priv_id);
190
191                 packet_reply = packet_create_reply(packet, "ii", ret, priv_id);
192                 if (packet_reply) {
193                         service_common_unicast_packet(tcb, packet_reply);
194                         packet_destroy(packet_reply);
195                 }
196
197                 packet_service = packet_create("del_noti_single", "ii", 1, priv_id);
198                 if (packet_service != NULL) {
199                         service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE);
200                         packet_destroy(packet_service);
201                 }
202         }
203 }
204
205 static void _handler_delete_multiple(struct tcb *tcb, struct packet *packet, void *data)
206 {
207         int ret = 0;
208         struct packet *packet_reply = NULL;
209         struct packet *packet_service = NULL;
210         char *pkgname = NULL;
211         notification_type_e type = 0;
212         int num_deleted = 0;
213         int *list_deleted = NULL;
214
215         if (packet_get(packet, "si", &pkgname, &type) == 2) {
216                 pkgname = get_string(pkgname);
217
218                 ret = notification_noti_delete_all(type, pkgname, &num_deleted, &list_deleted);
219
220                 packet_reply = packet_create_reply(packet, "ii", ret, num_deleted);
221                 if (packet_reply) {
222                         service_common_unicast_packet(tcb, packet_reply);
223                         packet_destroy(packet_reply);
224                 }
225
226                 if (num_deleted > 0) {
227                         if (num_deleted <= NOTIFICATION_DEL_PACKET_UNIT) {
228                                 packet_service = create_packet_from_deleted_list(num_deleted, list_deleted, 0);
229
230                                 if (packet_service) {
231                                         service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE);
232                                         packet_destroy(packet_service);
233                                 }
234                         } else {
235                                 int set = 0;
236                                 int set_total = num_deleted / NOTIFICATION_DEL_PACKET_UNIT;
237
238                                 for (set = 0; set <= set_total; set++) {
239                                         packet_service = create_packet_from_deleted_list(num_deleted,
240                                                         list_deleted, set * NOTIFICATION_DEL_PACKET_UNIT);
241
242                                         if (packet_service) {
243                                                 service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE);
244                                                 packet_destroy(packet_service);
245                                         }
246                                 }
247                         }
248                 }
249
250                 if (list_deleted != NULL) {
251                         free(list_deleted);
252                         list_deleted = NULL;
253                 }
254         }
255 }
256
257 static void _handler_service_register(struct tcb *tcb, struct packet *packet, void *data)
258 {
259         struct packet *packet_reply;
260         int ret;
261
262         ret = tcb_client_type_set(tcb, TCB_CLIENT_TYPE_SERVICE);
263
264         packet_reply = packet_create_reply(packet, "i", ret);
265         if (packet_reply) {
266                 service_common_unicast_packet(tcb, packet_reply);
267                 packet_destroy(packet_reply);
268         }
269 }
270
271 /*!
272  * SERVICE THREAD
273  */
274 static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
275 {
276         int i = 0;
277         const char *command;
278         static struct noti_service service_req_table[] = {
279                 {
280                         .cmd = "add_noti",
281                         .handler = _handler_insert,
282                 },
283                 {
284                         .cmd = "update_noti",
285                         .handler = _handler_update,
286                 },
287                 {
288                         .cmd = "refresh_noti",
289                         .handler = _handler_refresh,
290                 },
291                 {
292                         .cmd = "del_noti_single",
293                         .handler = _handler_delete_single,
294                 },
295                 {
296                         .cmd = "del_noti_multiple",
297                         .handler = _handler_delete_multiple,
298                 },
299                 {
300                         .cmd = "service_register",
301                         .handler = _handler_service_register,
302                 },
303                 {
304                         .cmd = NULL,
305                         .handler = NULL,
306                 },
307         };
308
309         if (!packet) {
310                 return 0;
311         }
312
313         command = packet_command(packet);
314         if (!command) {
315                 return -EINVAL;
316         }
317
318         switch (packet_type(packet)) {
319         case PACKET_REQ:
320                 /* Need to send reply packet */
321                 for (i = 0; service_req_table[i].cmd; i++) {
322                         if (strcmp(service_req_table[i].cmd, command))
323                                 continue;
324
325                         service_req_table[i].handler(tcb, packet, data);
326                         break;
327                 }
328
329                 break;
330         case PACKET_REQ_NOACK:
331                 break;
332         case PACKET_ACK:
333                 break;
334         default:
335                 return -EINVAL;
336         }
337
338         /*!
339          * return value has no meanning,
340          * it will be printed by dlogutil.
341          */
342         return 0;
343 }
344
345
346 /*!
347  * MAIN THREAD
348  * Do not try to do anyother operation in these functions
349  */
350 int notification_service_init(void)
351 {
352         if (s_info.svc_ctx) {
353                 return -1;
354         }
355
356         s_info.svc_ctx = service_common_create(NOTIFICATION_ADDR, service_thread_main, NULL);
357         if (!s_info.svc_ctx) {
358                 return -1;
359         }
360
361         return 0;
362 }
363
364 int notification_service_fini(void)
365 {
366         if (!s_info.svc_ctx)
367                 return -1;
368
369         service_common_destroy(s_info.svc_ctx);
370         return 0;
371 }
372
373 /* End of a file */