Add changed callback call logic when register service
[platform/core/appfw/badge.git] / src / badge_ipc.c
1 /*
2  *  libbadge
3  *
4  * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Youngjoo Park <yjoo93.park@samsung.com>,
7  *      Seungtaek Chung <seungtaek.chung@samsung.com>, Youngsub Ko <ys4610.ko@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the License);
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an AS IS BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <gio/gio.h>
26
27 #include <vconf.h>
28
29 #include "badge.h"
30 #include "badge_log.h"
31 #include "badge_error.h"
32 #include "badge_internal.h"
33 #include "badge_ipc.h"
34
35
36 #define PROVIDER_BUS_NAME "org.tizen.data_provider_service"
37 #define PROVIDER_OBJECT_PATH "/org/tizen/data_provider_service"
38 #define PROVIDER_BADGE_INTERFACE_NAME "org.tizen.data_provider_badge_service"
39
40
41 #define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
42 #define DBUS_PATH_DBUS "/org/freedesktop/DBus"
43 #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus"
44
45
46 typedef struct _task_list task_list;
47 struct _task_list {
48         task_list *prev;
49         task_list *next;
50
51         void (*task_cb) (void *data);
52         void *data;
53 };
54 static task_list *g_task_list;
55
56 static GDBusConnection *_gdbus_conn = NULL;
57 static int monitor_id = 0;
58 static int provider_monitor_id = 0;
59 static int is_master_started = 0;
60
61 static void _do_deferred_task(void);
62
63 int badge_ipc_is_master_ready(void)
64 {
65         GVariant *result = NULL;
66         GError *err = NULL;
67         gboolean name_exist;
68
69         result = g_dbus_connection_call_sync(
70                         _gdbus_conn,
71                         DBUS_SERVICE_DBUS,
72                         DBUS_PATH_DBUS,
73                         DBUS_INTERFACE_DBUS,
74                         "NameHasOwner",
75                         g_variant_new("(s)", PROVIDER_BUS_NAME),
76                         G_VARIANT_TYPE("(b)"),
77                         G_DBUS_CALL_FLAGS_NONE,
78                         -1,
79                         NULL,
80                         &err);
81
82         if (err || (result == NULL)) {
83                 if (err) {
84                         ERR("No reply. error = %s", err->message);
85                         g_error_free(err);
86                 }
87                 is_master_started = 0;
88         } else {
89                 g_variant_get(result, "(b)", &name_exist);
90
91                 if (!name_exist) {
92                         ERR("Name not exist %s", PROVIDER_BUS_NAME);
93                         ERR("the master has been stopped");
94                         is_master_started = 0;
95                 } else {
96                         DBG("the master has been started");
97                         is_master_started = 1;
98                 }
99         }
100
101         if (result)
102                 g_variant_unref(result);
103
104         return is_master_started;
105 }
106
107 int badge_ipc_add_deferred_task(
108                 void (*badge_add_deferred_task)(void *data),
109                 void *user_data)
110 {
111         task_list *list;
112         task_list *list_new;
113
114         list_new = (task_list *) malloc(sizeof(task_list));
115
116         if (list_new == NULL)
117                 return BADGE_ERROR_OUT_OF_MEMORY;
118
119         list_new->next = NULL;
120         list_new->prev = NULL;
121
122         list_new->task_cb = badge_add_deferred_task;
123         list_new->data = user_data;
124
125         if (g_task_list == NULL) {
126                 g_task_list = list_new;
127         } else {
128                 list = g_task_list;
129
130                 while (list->next != NULL)
131                         list = list->next;
132
133                 list->next = list_new;
134                 list_new->prev = list;
135         }
136         return BADGE_ERROR_NONE;
137 }
138
139 int badge_ipc_del_deferred_task(
140                 void (*badge_add_deferred_task)(void *data))
141 {
142         task_list *list_del;
143         task_list *list_prev;
144         task_list *list_next;
145
146         list_del = g_task_list;
147
148         if (list_del == NULL)
149                 return BADGE_ERROR_INVALID_PARAMETER;
150
151         while (list_del->prev != NULL)
152                 list_del = list_del->prev;
153
154         do {
155                 if (list_del->task_cb == badge_add_deferred_task) {
156                         list_prev = list_del->prev;
157                         list_next = list_del->next;
158
159                         if (list_prev == NULL)
160                                 g_task_list = list_next;
161                         else
162                                 list_prev->next = list_next;
163
164                         if (list_next == NULL) {
165                                 if (list_prev != NULL)
166                                         list_prev->next = NULL;
167
168                         } else {
169                                 list_next->prev = list_prev;
170                         }
171
172                         free(list_del);
173                         return BADGE_ERROR_NONE;
174                 }
175                 list_del = list_del->next;
176         } while (list_del != NULL);
177
178         return BADGE_ERROR_INVALID_PARAMETER;
179 }
180
181 static void _do_deferred_task(void)
182 {
183         task_list *list_do;
184         task_list *list_temp;
185
186         if (g_task_list == NULL)
187                 return;
188
189         list_do = g_task_list;
190         g_task_list = NULL;
191
192         while (list_do->prev != NULL)
193                 list_do = list_do->prev;
194
195         while (list_do != NULL) {
196                 if (list_do->task_cb != NULL) {
197                         list_do->task_cb(list_do->data);
198                         DBG("called:%p", list_do->task_cb);
199                 }
200                 list_temp = list_do->next;
201                 free(list_do);
202                 list_do = list_temp;
203         }
204 }
205
206 /*
207  * dbus handler implementation
208  */
209 static void _insert_badge_notify(GVariant *parameters)
210 {
211         char *pkgname = NULL;
212
213         g_variant_get(parameters, "(&s)", &pkgname);
214         badge_changed_cb_call(BADGE_ACTION_CREATE, pkgname, 0);
215 }
216
217 static void _delete_badge_notify(GVariant *parameters)
218 {
219         char *pkgname = NULL;
220
221         g_variant_get(parameters, "(&s)", &pkgname);
222         badge_changed_cb_call(BADGE_ACTION_REMOVE, pkgname, 0);
223 }
224
225 static void _set_badge_count_notify(GVariant *parameters)
226 {
227         char *pkgname = NULL;
228         int count = 0;
229
230         g_variant_get(parameters, "(&si)", &pkgname, &count);
231         badge_changed_cb_call(BADGE_ACTION_UPDATE, pkgname, count);
232 }
233
234 static void _set_disp_option_notify(GVariant *parameters)
235 {
236         char *pkgname = NULL;
237         int is_display = 0;
238
239         g_variant_get(parameters, "(&si)", &pkgname, &is_display);
240         badge_changed_cb_call(BADGE_ACTION_CHANGED_DISPLAY, pkgname, is_display);
241 }
242
243 static void _handle_badge_notify(GDBusConnection *connection,
244                 const gchar     *sender_name,
245                 const gchar     *object_path,
246                 const gchar     *interface_name,
247                 const gchar     *signal_name,
248                 GVariant        *parameters,
249                 gpointer         user_data)
250 {
251         DBG("signal_name: %s", signal_name);
252         if (g_strcmp0(signal_name, "insert_badge_notify") == 0)
253                 _insert_badge_notify(parameters);
254         else if (g_strcmp0(signal_name, "delete_badge_notify") == 0)
255                 _delete_badge_notify(parameters);
256         else if (g_strcmp0(signal_name, "set_badge_count_notify") == 0)
257                 _set_badge_count_notify(parameters);
258         else if (g_strcmp0(signal_name, "set_disp_option_notify") == 0)
259                 _set_disp_option_notify(parameters);
260 }
261
262 static int _dbus_init(void)
263 {
264         GError *error = NULL;
265
266         if (_gdbus_conn == NULL) {
267                 _gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
268                 if (_gdbus_conn == NULL) {
269                         if (error != NULL) {
270                                 ERR("Failed to get dbus [%s]", error->message);
271                                 g_error_free(error);
272                         }
273                         return BADGE_ERROR_IO_ERROR;
274                 }
275                 badge_error_quark();
276         }
277
278         return BADGE_ERROR_NONE;
279 }
280
281 static int _dbus_signal_init()
282 {
283         int ret = BADGE_ERROR_NONE;
284         int id;
285
286         if (monitor_id == 0) {
287                 DBG("get dbus connection success");
288                 id = g_dbus_connection_signal_subscribe(_gdbus_conn,
289                                 PROVIDER_BUS_NAME,
290                                 PROVIDER_BADGE_INTERFACE_NAME,  /*   interface */
291                                 NULL,                           /*   member */
292                                 PROVIDER_OBJECT_PATH,           /*   path */
293                                 NULL,                           /*   arg0 */
294                                 G_DBUS_SIGNAL_FLAGS_NONE,
295                                 _handle_badge_notify,
296                                 NULL,
297                                 NULL);
298
299                 DBG("subscribe id : %d", id);
300                 if (id == 0) {
301                         ret = BADGE_ERROR_IO_ERROR;
302                         ERR("Failed to _register_noti_dbus_interface");
303                 } else {
304                         monitor_id = id;
305                 }
306         }
307
308         return ret;
309 }
310
311 /*
312  * implement user request
313  */
314 static int _send_sync_badge(GVariant *body, GDBusMessage **reply, char *cmd)
315 {
316         GError *err = NULL;
317         GDBusMessage *msg;
318         int ret = BADGE_ERROR_NONE;
319
320         msg = g_dbus_message_new_method_call(
321                         PROVIDER_BUS_NAME,
322                         PROVIDER_OBJECT_PATH,
323                         PROVIDER_BADGE_INTERFACE_NAME,
324                         cmd);
325         if (!msg) {
326                 ERR("Can't allocate new method call");
327                 if (body)
328                         g_variant_unref(body);
329                 return BADGE_ERROR_OUT_OF_MEMORY;
330         }
331
332         if (body != NULL)
333                 g_dbus_message_set_body(msg, body);
334
335         *reply = g_dbus_connection_send_message_with_reply_sync(
336                         _gdbus_conn,
337                         msg,
338                         G_DBUS_SEND_MESSAGE_FLAGS_NONE,
339                         -1,
340                         NULL,
341                         NULL,
342                         &err);
343
344         g_object_unref(msg);
345
346         if (!*reply) {
347                 ret = BADGE_ERROR_SERVICE_NOT_READY;
348                 if (err != NULL) {
349                         ERR("No reply. cmd = %s,  error = %s", cmd, err->message);
350                         if (err->code == G_DBUS_ERROR_ACCESS_DENIED)
351                                 ret = BADGE_ERROR_PERMISSION_DENIED;
352                         g_error_free(err);
353                 }
354                 return ret;
355         }
356
357         if (g_dbus_message_to_gerror(*reply, &err)) {
358                 ret = err->code;
359                 ERR("_send_sync_badge cmd = %s, error %s", cmd, err->message);
360                 if (err->code == G_DBUS_ERROR_ACCESS_DENIED)
361                         ret = BADGE_ERROR_PERMISSION_DENIED;
362                 g_error_free(err);
363                 return ret;
364         }
365         ERR("_send_sync_badge done !!");
366         return BADGE_ERROR_NONE;
367
368 }
369
370 static int _send_service_register()
371 {
372         GDBusMessage *reply = NULL;
373         int result;
374
375         result = _send_sync_badge(NULL, &reply, "badge_service_register");
376
377         if (reply)
378                 g_object_unref(reply);
379
380         badge_changed_cb_call(BADGE_ACTION_SERVICE_READY, NULL, 0);
381         DBG("_send_service_register dones");
382         return result;
383 }
384
385 static int _ipc_monitor_register(void)
386 {
387         DBG("register a service\n");
388
389         return  _send_service_register();
390 }
391
392 static void _on_name_appeared(GDBusConnection *connection,
393                 const gchar     *name,
394                 const gchar     *name_owner,
395                 gpointer         user_data)
396 {
397         DBG("name appeared : %s", name);
398         is_master_started = 1;
399         _ipc_monitor_register();
400
401         _do_deferred_task();
402 }
403
404 static void _on_name_vanished(GDBusConnection *connection,
405                 const gchar     *name,
406                 gpointer         user_data)
407 {
408         DBG("name vanished : %s", name);
409         is_master_started = 0;
410 }
411
412 int badge_ipc_monitor_init(void)
413 {
414         DBG("register a service\n");
415         int ret = BADGE_ERROR_NONE;
416
417         ret = _dbus_init();
418         if (ret != BADGE_ERROR_NONE) {
419                 ERR("Can't init dbus %d", ret);
420                 return ret;
421         }
422
423         ret = _dbus_signal_init();
424         if (ret != BADGE_ERROR_NONE) {
425                 ERR("Can't init dbus signal %d", ret);
426                 return ret;
427         }
428
429         ret = _ipc_monitor_register();
430         if (ret != BADGE_ERROR_NONE) {
431                 ERR("Can't init ipc_monitor_register %d", ret);
432                 return ret;
433         }
434
435         if (provider_monitor_id == 0) {
436                 provider_monitor_id = g_bus_watch_name_on_connection(
437                                 _gdbus_conn,
438                                 PROVIDER_BUS_NAME,
439                                 G_BUS_NAME_WATCHER_FLAGS_NONE,
440                                 _on_name_appeared,
441                                 _on_name_vanished,
442                                 NULL,
443                                 NULL);
444
445                 if (provider_monitor_id == 0) {
446                         ERR("watch on name fail");
447                         g_dbus_connection_signal_unsubscribe(_gdbus_conn, monitor_id);
448                         monitor_id = 0;
449                         return BADGE_ERROR_IO_ERROR;
450                 }
451         }
452
453         return ret;
454 }
455
456 int badge_ipc_monitor_fini(void)
457 {
458         if (provider_monitor_id) {
459                 g_bus_unwatch_name(provider_monitor_id);
460                 provider_monitor_id = 0;
461         }
462
463         if (monitor_id) {
464                 g_dbus_connection_signal_unsubscribe(_gdbus_conn, monitor_id);
465                 monitor_id = 0;
466         }
467         return BADGE_ERROR_NONE;
468 }
469
470 int badge_ipc_request_insert(const char *pkgname, const char *writable_pkg, const char *caller)
471 {
472         int result;
473         GDBusMessage *reply = NULL;
474         GVariant *body;
475
476         result = _dbus_init();
477         if (result != BADGE_ERROR_NONE) {
478                 ERR("Can't init dbus %d", result);
479                 return result;
480         }
481
482         body = g_variant_new("(sss)", pkgname, writable_pkg, caller);
483         if (!body) {
484                 ERR("Cannot create gvariant. Out of memory.");
485                 return BADGE_ERROR_OUT_OF_MEMORY;
486         }
487
488         result = _send_sync_badge(body, &reply, "insert_badge");
489
490         if (reply)
491                 g_object_unref(reply);
492
493         DBG("badge_ipc_request_insert done [result: %d]", result);
494         return result;
495 }
496
497 int badge_ipc_request_delete(const char *pkgname, const char *caller)
498 {
499         int result;
500         GDBusMessage *reply = NULL;
501         GVariant *body;
502
503         result = _dbus_init();
504         if (result != BADGE_ERROR_NONE) {
505                 ERR("Can't init dbus %d", result);
506                 return result;
507         }
508         body = g_variant_new("(ss)", pkgname, caller);
509
510         result = _send_sync_badge(body, &reply, "delete_badge");
511
512         if (reply)
513                 g_object_unref(reply);
514
515         DBG("badge_ipc_request_delete done [result: %d]", result);
516         return result;
517 }
518
519 int badge_ipc_request_set_count(const char *pkgname, const char *caller, int count)
520 {
521         int result;
522         GDBusMessage *reply = NULL;
523         GVariant *body;
524
525         result = _dbus_init();
526         if (result != BADGE_ERROR_NONE) {
527                 ERR("Can't init dbus %d", result);
528                 return result;
529         }
530         body = g_variant_new("(ssi)", pkgname, caller, count);
531
532         result = _send_sync_badge(body, &reply, "set_badge_count");
533
534         if (reply)
535             g_object_unref(reply);
536
537         DBG("badge_ipc_request_set_count done [result: %d]", result);
538         return result;
539 }
540
541 int badge_ipc_request_get_count(const char *pkgname, unsigned int *count)
542 {
543         int result;
544         GDBusMessage *reply = NULL;
545         GVariant *body;
546         GVariant *reply_body;
547         int ret_count;
548
549         result = _dbus_init();
550         if (result != BADGE_ERROR_NONE) {
551                 ERR("Can't init dbus %d", result);
552                 return result;
553         }
554         body = g_variant_new("(s)", pkgname);
555
556         result = _send_sync_badge(body, &reply, "get_badge_count");
557         if (result == BADGE_ERROR_NONE) {
558                 reply_body = g_dbus_message_get_body(reply);
559                 g_variant_get(reply_body, "(i)", &ret_count);
560                 *count = ret_count;
561         }
562
563         if (reply)
564                 g_object_unref(reply);
565
566         DBG("badge_ipc_request_get_count done [result: %d]", result);
567         return result;
568 }
569
570 int badge_ipc_request_set_display(const char *pkgname, const char *caller, unsigned int display_option)
571 {
572         int result;
573         GDBusMessage *reply = NULL;
574         GVariant *body;
575
576         result = _dbus_init();
577         if (result != BADGE_ERROR_NONE) {
578                 ERR("Can't init dbus %d", result);
579                 return result;
580         }
581         body = g_variant_new("(ssi)", pkgname, caller, display_option);
582
583         result = _send_sync_badge(body, &reply, "set_disp_option");
584         if (reply)
585                 g_object_unref(reply);
586
587         DBG("badge_ipc_request_set_display done [result: %d]", result);
588         return result;
589 }
590
591 int badge_ipc_request_get_display(const char *pkgname, unsigned int *is_display)
592 {
593         int result ;
594         GDBusMessage *reply = NULL;
595         GVariant *body ;
596         GVariant *reply_body;
597         unsigned int ret_is_display;
598
599         result = _dbus_init();
600         if (result != BADGE_ERROR_NONE) {
601                 ERR("Can't init dbus %d", result);
602                 return result;
603         }
604         body = g_variant_new("(s)", pkgname);
605
606         result = _send_sync_badge(body, &reply, "get_disp_option");
607         if (result == BADGE_ERROR_NONE) {
608                 reply_body = g_dbus_message_get_body(reply);
609                 g_variant_get(reply_body, "(i)", &ret_is_display);
610                 *is_display = ret_is_display;
611         }
612
613         if (reply)
614                 g_object_unref(reply);
615
616         DBG("badge_ipc_request_get_display done [result: %d]", result);
617         return result;
618 }
619
620 int badge_ipc_setting_property_set(const char *pkgname, const char *property, const char *value)
621 {
622         int result;
623         GDBusMessage *reply = NULL;
624         GVariant *body;
625
626         result = _dbus_init();
627         if (result != BADGE_ERROR_NONE) {
628                 ERR("Can't init dbus %d", result);
629                 return result;
630         }
631         body = g_variant_new("(sss)", pkgname, property, value);
632
633         result = _send_sync_badge(body, &reply, "set_noti_property");
634         if (reply)
635                 g_object_unref(reply);
636
637         DBG("badge_ipc_setting_property_set done [result: %d]", result);
638         return result;
639 }
640
641 int badge_ipc_setting_property_get(const char *pkgname, const char *property, char **value)
642 {
643         int result;
644         GDBusMessage *reply = NULL;
645         GVariant *body;
646         GVariant *reply_body;
647         char *ret_val = NULL;
648
649         result = _dbus_init();
650         if (result != BADGE_ERROR_NONE) {
651                 ERR("Can't init dbus %d", result);
652                 return result;
653         }
654         body = g_variant_new("(ss)", pkgname, property);
655
656         result = _send_sync_badge(body, &reply, "get_noti_property");
657         if (result == BADGE_ERROR_NONE) {
658                 reply_body = g_dbus_message_get_body(reply);
659                 g_variant_get(reply_body, "(&s)", ret_val);
660
661                 if (ret_val != NULL)
662                         *value = strdup(ret_val);
663                 else
664                         result = BADGE_ERROR_IO_ERROR;
665         }
666         if (reply)
667                 g_object_unref(reply);
668
669         DBG("badge_ipc_setting_property_get done [result: %d]", result);
670         return result;
671 }
672
673