8d9b6c164b7c05b7177f4e34551e7de99ddad7e5
[platform/core/appfw/slp-pkgmgr.git] / comm / comm_client_gdbus.c
1 /*
2  * slp-pkgmgr
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>,
7  * Jaeho Lee <jaeho81.lee@samsung.com>, Shobhit Srivastava <shobhit.s@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
24 /*
25  * comm_client_gdbus.c
26  * comm_client library using gdbus
27  */
28
29 #include <glib.h>
30 #include <gio/gio.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 #include <glib.h>
36 #include <gio/gio.h>
37
38 #include "comm_config.h"
39 #include "comm_client.h"
40 #include "comm_debug.h"
41
42 /*******************
43  * ADT description
44  */
45
46 /* Storing status_cb */
47 struct signal_callback_data {
48         int type;
49         status_cb cb;
50         void *cb_data;
51 };
52
53 /* comm_client ADT */
54 struct comm_client {
55         guint subscription_id;
56         GDBusConnection *conn;
57         struct signal_callback_data *sig_cb_data;
58 };
59
60 static int __get_signal_type(const char *name)
61 {
62         if (name == NULL)
63                 return -1;
64
65         if (strcmp(name, COMM_STATUS_BROADCAST_SIGNAL_STATUS) == 0)
66                 return COMM_STATUS_BROADCAST_ALL;
67         else if (strcmp(name, COMM_STATUS_BROADCAST_EVENT_INSTALL) == 0)
68                 return COMM_STATUS_BROADCAST_INSTALL;
69         else if (strcmp(name, COMM_STATUS_BROADCAST_EVENT_UNINSTALL) == 0)
70                 return COMM_STATUS_BROADCAST_UNINSTALL;
71         else if (strcmp(name, COMM_STATUS_BROADCAST_EVENT_MOVE) == 0)
72                 return COMM_STATUS_BROADCAST_MOVE;
73         else if (strcmp(name, COMM_STATUS_BROADCAST_EVENT_INSTALL_PROGRESS) == 0)
74                 return COMM_STATUS_BROADCAST_INSTALL_PROGRESS;
75         else if (strcmp(name, COMM_STATUS_BROADCAST_EVENT_UPGRADE) == 0)
76                 return COMM_STATUS_BROADCAST_UPGRADE;
77         else if (strcmp(name, COMM_STATUS_BROADCAST_EVENT_GET_SIZE) == 0)
78                 return COMM_STATUS_BROADCAST_GET_SIZE;
79         else
80                 return -1;
81 }
82
83 /**
84  * signal handler filter
85  * Filter signal, and run user callback
86  */
87 void _on_signal_handle_filter(GDBusConnection *conn,
88                 const gchar *sender_name,
89                 const gchar *object_path,
90                 const gchar *interface_name,
91                 const gchar *signal_name,
92                 GVariant *parameters,
93                 gpointer user_data)
94 {
95         if (interface_name && strcmp(interface_name, "org.tizen.pkgmgr.signal")) {
96                 DBG("Interface name did not match. Drop the message");
97                 return;
98         }
99
100         int status_type;
101         /* Values to be received by signal */
102         uid_t target_uid;
103         char *req_id = NULL;
104         char *pkg_type = NULL;
105         char *pkgid = NULL;
106         char *key = NULL;
107         char *val = NULL;
108
109         /* User's signal handler */
110         struct signal_callback_data *sig_cb_data;
111         if (user_data)
112                 sig_cb_data = (struct signal_callback_data *)user_data;
113         else
114                 return;
115
116         status_type = __get_signal_type(signal_name);
117         if (status_type < 0 || !(status_type & sig_cb_data->type))
118                 return;
119
120         g_variant_get(parameters, "(u&s&s&s&s&s)",
121                                 &target_uid, &req_id, &pkg_type, &pkgid, &key, &val);
122
123         /* Run signal callback if exist */
124         if (sig_cb_data && sig_cb_data->cb)
125                 sig_cb_data->cb(sig_cb_data->cb_data, target_uid, req_id,
126                                 pkg_type, pkgid, key, val);
127
128         return;
129 }
130
131 /**
132  * signal_callback_data free function
133  * Just free it!
134  */
135 void _free_sig_cb_data(void *data)
136 {
137         struct signal_callback_data *sig_cb_data = NULL;
138         sig_cb_data = (struct signal_callback_data *)data;
139         free(sig_cb_data);
140 }
141
142 /*******************
143  * API description
144  */
145
146 /**
147  * Create a new comm_client object
148  */
149 comm_client *comm_client_new(void)
150 {
151         GError *error = NULL;
152         comm_client *cc = NULL;
153
154         /* Allocate memory for ADT:comm_client */
155 #if !GLIB_CHECK_VERSION(2,35,0)
156         g_type_init();
157 #endif
158         cc = calloc(1, sizeof(comm_client));
159         if (NULL == cc) {
160                 ERR("No memory");
161                 return NULL;
162         }
163
164         /* Connect to gdbus. Gets shared BUS */
165         cc->conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
166         if (error) {
167                 ERR("gdbus connection error (%s)", error->message);
168                 g_error_free(error);
169                 goto ERROR_CLEANUP;
170         }
171         if (NULL == cc->conn) {
172                 ERR("gdbus connection is not set, even gdbus error isn't raised");
173                 goto ERROR_CLEANUP;
174         }
175         return cc;
176
177  ERROR_CLEANUP:
178         if (cc)
179                 free(cc);
180         return NULL;
181 }
182
183 /**
184  * Free comm_client object
185  */
186 int comm_client_free(comm_client *cc)
187 {
188         if (!cc)
189                 return -1;
190         if (!(cc->conn) || g_dbus_connection_is_closed(cc->conn)) {
191                 ERR("Invalid gdbus connection");
192                 return -2;
193         }
194
195         if (cc->sig_cb_data) {
196                 g_dbus_connection_signal_unsubscribe(cc->conn, cc->subscription_id);
197                 /* TODO: Is it needed to free cc->sig_cb_data here? */
198                 /* _free_sig_cb_data(cc->sig_cb_data); */
199         }
200
201         /* Cleanup ADT */
202         /* flush remaining buffer: blocking mode */
203         g_dbus_connection_flush_sync(cc->conn, NULL, NULL);
204
205         /* Free signal filter if signal callback is exist */
206
207         /* just unref because it is shared BUS.
208         If ref count is 0 it will get free'd automatically
209         */
210         g_object_unref(cc->conn);
211         free(cc);
212
213         return 0;
214 }
215
216 /**
217  * Request a message
218  */
219 int
220 comm_client_request(comm_client *cc, const char *req_id, const int req_type,
221                 const char *pkg_type, const char *pkgid, const char *args,
222                 uid_t uid, int is_block)
223 {
224         GError *error = NULL;
225         gint rc = -1;
226         GDBusProxy *proxy;
227         GVariant *result;
228
229         proxy = g_dbus_proxy_new_sync(cc->conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
230                         COMM_PKGMGR_DBUS_SERVICE, COMM_PKGMGR_DBUS_OBJECT_PATH,
231                         COMM_PKGMGR_DBUS_INTERFACE, NULL, &error);
232         if (proxy == NULL) {
233                 ERR("failed to get proxy object: %s", error->message);
234                 g_error_free(error);
235                 return -1;
236         }
237
238         /* Assign default values if NULL (NULL is not allowed) */
239         if (req_id == NULL)
240                 req_id = "tmp_reqid";
241         if (pkg_type == NULL)
242                 pkg_type = "none";
243         if (pkgid == NULL)
244                 pkgid = "";
245         if (args == NULL)
246                 args = "";
247
248         result = g_dbus_proxy_call_sync(proxy, "Request", g_variant_new("(sisssi)", req_id, req_type, pkg_type, pkgid, args, uid),
249                         G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
250         if (result == NULL) {
251                 ERR("failed to call %s", error->message);
252                 g_error_free(error);
253                 g_object_unref(proxy);
254                 return -1;
255         }
256
257         g_variant_get(result, "(i)", &rc);
258
259         return rc == 0 ? COMM_RET_OK : COMM_RET_ERROR;
260 }
261
262 /**
263  * Set a callback for status signal
264  */
265 int
266 comm_client_set_status_callback(int comm_status_type, comm_client *cc, status_cb cb, void *cb_data)
267 {
268         int r = COMM_RET_ERROR;
269
270         if (NULL == cc)
271                 return COMM_RET_ERROR;
272
273         /* Create new sig_cb_data */
274         cc->sig_cb_data = calloc(1, sizeof(struct signal_callback_data));
275         if ( cc->sig_cb_data ) {
276                 (cc->sig_cb_data)->type = comm_status_type;
277                 (cc->sig_cb_data)->cb = cb;
278                 (cc->sig_cb_data)->cb_data = cb_data;
279         } else {
280                 r = COMM_RET_ERROR;
281                 goto ERROR_CLEANUP;
282         }
283         /* Add a filter for signal */
284         cc->subscription_id = g_dbus_connection_signal_subscribe(cc->conn, NULL, "org.tizen.pkgmgr.signal",
285                 NULL, NULL, NULL, G_DBUS_SIGNAL_FLAGS_NONE,
286                 _on_signal_handle_filter, (gpointer)cc->sig_cb_data, _free_sig_cb_data);
287         if (!cc->subscription_id) {
288                 ERR("Failed to add filter\n");
289                 r = COMM_RET_ERROR;
290                 goto ERROR_CLEANUP;
291         }
292
293         return COMM_RET_OK;
294
295  ERROR_CLEANUP:
296         ERR("General error");
297         return r;
298 }
299