Release version 0.4.9
[platform/core/appfw/librua.git] / src / rua_dbus.c
1 /*
2  * Copyright (c) 2017 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 <stdlib.h>
19
20 #include <glib.h>
21 #include <gio/gio.h>
22 #include <dlog.h>
23
24 #include "rua.h"
25 #include "rua_dbus.h"
26 #include "rua_private.h"
27
28 #define RUA_INTERFACE "org.tizen.rua"
29 #define RUA_PATH "/org/tizen/rua"
30 #define RUA_SIGNAL_DATA_UPDATE "dataupdate"
31
32 struct cb_data {
33         int callback_id;
34         rua_history_update_cb callback;
35         void *user_data;
36 };
37
38 static GDBusConnection *conn;
39 static guint s_id;
40
41 static gint atomic_callback_id;
42 static GHashTable *callback_hash_table;
43
44 static void __foreach_callback(gpointer key, gpointer value,
45                 gpointer user_data);
46 static void __signal_handler(GDBusConnection *connection,
47                                         const gchar *sender_name,
48                                         const gchar *object_path,
49                                         const gchar *interface_name,
50                                         const gchar *signal_name,
51                                         GVariant *parameters,
52                                         gpointer user_data);
53 static void __rua_dbus_init(void);
54 static void __rua_dbus_exit(void);
55
56 int rua_dbus_send_update_signal(update_type type)
57 {
58         __rua_dbus_init();
59         GError *err = NULL;
60
61         if (g_dbus_connection_emit_signal(conn,
62                                 NULL,
63                                 RUA_PATH,
64                                 RUA_INTERFACE,
65                                 RUA_SIGNAL_DATA_UPDATE,
66                                 g_variant_new("(i)", type),
67                                 &err) == FALSE) {
68                 LOGE("g_dbus_connection_emit_signal() is failed. %s",
69                                 err->message);
70                 g_clear_error(&err);
71                 __rua_dbus_exit();
72                 return -1;
73         }
74
75         if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) {
76                 LOGE("g_dbus_connection_flush_sync() is failed. %s",
77                                 err->message);
78                 g_clear_error(&err);
79                 __rua_dbus_exit();
80                 return -1;
81         }
82
83         g_clear_error(&err);
84
85         __rua_dbus_exit();
86
87         return 0;
88 }
89
90 int rua_dbus_signal_subscribe(rua_history_update_cb callback,
91                 void *user_data, int *callback_id)
92 {
93         struct cb_data *cd = NULL;
94
95         if (s_id == 0) {
96                 __rua_dbus_init();
97
98                 s_id = g_dbus_connection_signal_subscribe(conn,
99                                 NULL,
100                                 RUA_INTERFACE,
101                                 RUA_SIGNAL_DATA_UPDATE,
102                                 RUA_PATH,
103                                 NULL,
104                                 G_DBUS_SIGNAL_FLAGS_NONE,
105                                 __signal_handler,
106                                 NULL,
107                                 NULL);
108
109                 if (s_id == 0) {
110                         LOGE("g_dbus_connection_signal_subscribe() is failed.");
111                         __rua_dbus_exit();
112                         return -1;
113                 }
114
115                 if (!callback_hash_table) {
116                         callback_hash_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
117                                         NULL, free);
118                         if (!callback_hash_table) {
119                                 LOGE("out of memory : g_hash_table_new() is failed");
120                                 __rua_dbus_exit();
121                                 return -1;
122                         }
123                 }
124         }
125
126         cd = (struct cb_data *)malloc(sizeof(struct cb_data));
127         if (!cd) {
128                 LOGE("out of memory : malloc() is failed");
129                 return -1;
130         }
131
132         g_atomic_int_inc(&atomic_callback_id);
133
134         cd->callback = callback;
135         cd->user_data = user_data;
136         cd->callback_id = atomic_callback_id;
137
138         g_hash_table_insert(callback_hash_table,
139                         GINT_TO_POINTER(cd->callback_id), (gpointer)cd);
140
141         *callback_id = cd->callback_id;
142
143         return 0;
144 }
145
146 int rua_dbus_signal_unsubscribe(int callback_id)
147 {
148         gboolean result = FALSE;
149         guint table_size = 0;
150
151         result = g_hash_table_remove(callback_hash_table, GINT_TO_POINTER(callback_id));
152         if (!result) {
153                 LOGE("g_hash_table_remove failed(%d is wrong)", callback_id);
154                 return -1;
155         }
156
157         table_size = g_hash_table_size(callback_hash_table);
158         if (s_id && table_size == 0) {
159                 g_dbus_connection_signal_unsubscribe(conn, s_id);
160                 g_hash_table_destroy(callback_hash_table);
161                 __rua_dbus_exit();
162                 callback_hash_table = NULL;
163                 s_id = 0;
164         }
165
166         return 0;
167 }
168
169 static void __foreach_callback(gpointer key, gpointer value,
170                 gpointer user_data)
171 {
172         char **table = NULL;
173         int nrows = 0;
174         int ncols = 0;
175         int r = 0;
176
177         struct cb_data *cd = (struct cb_data *)value;
178
179         r = rua_history_load_db(&table, &nrows, &ncols);
180         if (r == -1)
181                 return;
182
183         if (cd->callback)
184                 cd->callback(table, nrows, ncols, cd->user_data);
185 }
186
187 static void __signal_handler(GDBusConnection *connection,
188                                         const gchar *sender_name,
189                                         const gchar *object_path,
190                                         const gchar *interface_name,
191                                         const gchar *signal_name,
192                                         GVariant *parameters,
193                                         gpointer user_data)
194 {
195         int update_type;
196
197         LOGI("__signal_handler");
198         if (g_strcmp0(signal_name, RUA_SIGNAL_DATA_UPDATE))
199                 return;
200
201         g_variant_get(parameters, "(i)", &update_type);
202
203         g_hash_table_foreach(callback_hash_table, __foreach_callback, NULL);
204 }
205
206 static void __rua_dbus_init(void)
207 {
208         if (!conn) {
209                 GError *err = NULL;
210                 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
211                 if (!conn) {
212                         LOGE("g_bus_get_sync() is failed. %s", err->message);
213                         g_error_free(err);
214                         return;
215                 }
216         }
217 }
218
219 static void __rua_dbus_exit(void)
220 {
221         if (conn) {
222                 g_object_unref(conn);
223                 conn = NULL;
224         }
225 }