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