Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / obexd / client / manager.c
1 /*
2  *
3  *  OBEX Client
4  *
5  *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <signal.h>
32 #include <syslog.h>
33
34 #include <glib.h>
35
36 #include "gdbus/gdbus.h"
37
38 #include "obexd/src/log.h"
39 #include "obexd/src/manager.h"
40 #include "transfer.h"
41 #include "session.h"
42 #include "bluetooth.h"
43 #include "opp.h"
44 #include "ftp.h"
45 #include "pbap.h"
46 #include "sync.h"
47 #include "map.h"
48 #include "manager.h"
49 #ifdef __TIZEN_PATCH__
50 #include "mns-tizen.h"
51 #endif
52 #define CLIENT_INTERFACE        "org.bluez.obex.Client1"
53 #define ERROR_INTERFACE         "org.bluez.obex.Error"
54 #define CLIENT_PATH             "/org/bluez/obex"
55
56 struct send_data {
57         DBusConnection *connection;
58         DBusMessage *message;
59 };
60
61 static GSList *sessions = NULL;
62
63 static void shutdown_session(struct obc_session *session)
64 {
65         obc_session_shutdown(session);
66         obc_session_unref(session);
67 }
68
69 #ifdef __TIZEN_PATCH__
70 void release_session(struct obc_session *session)
71 {
72         DBG("+");
73         sessions = g_slist_remove(sessions, session);
74         shutdown_session(session);
75         DBG("-");
76 }
77 #else
78 static void release_session(struct obc_session *session)
79 {
80         sessions = g_slist_remove(sessions, session);
81         shutdown_session(session);
82 }
83 #endif
84
85 static void unregister_session(void *data)
86 {
87         struct obc_session *session = data;
88
89         if (g_slist_find(sessions, session) == NULL)
90                 return;
91
92         sessions = g_slist_remove(sessions, session);
93         obc_session_unref(session);
94 }
95
96 static void create_callback(struct obc_session *session,
97                                                 struct obc_transfer *transfer,
98                                                 GError *err, void *user_data)
99 {
100         struct send_data *data = user_data;
101         const char *path;
102
103         if (err != NULL) {
104                 DBusMessage *error = g_dbus_create_error(data->message,
105                                         ERROR_INTERFACE ".Failed",
106                                         "%s", err->message);
107                 g_dbus_send_message(data->connection, error);
108                 shutdown_session(session);
109                 goto done;
110         }
111
112
113         path = obc_session_register(session, unregister_session);
114         if (path == NULL) {
115                 DBusMessage *error = g_dbus_create_error(data->message,
116                                         ERROR_INTERFACE ".Failed",
117                                         NULL);
118                 g_dbus_send_message(data->connection, error);
119                 shutdown_session(session);
120                 goto done;
121         }
122
123         sessions = g_slist_append(sessions, session);
124         g_dbus_send_reply(data->connection, data->message,
125                                 DBUS_TYPE_OBJECT_PATH, &path,
126                                 DBUS_TYPE_INVALID);
127
128 done:
129         dbus_message_unref(data->message);
130         dbus_connection_unref(data->connection);
131         g_free(data);
132 }
133
134 static int parse_device_dict(DBusMessageIter *iter,
135                 const char **source, const char **target, uint8_t *channel)
136 {
137         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_DICT_ENTRY) {
138                 DBusMessageIter entry, value;
139                 const char *key;
140
141                 dbus_message_iter_recurse(iter, &entry);
142                 dbus_message_iter_get_basic(&entry, &key);
143
144                 dbus_message_iter_next(&entry);
145                 dbus_message_iter_recurse(&entry, &value);
146
147                 switch (dbus_message_iter_get_arg_type(&value)) {
148                 case DBUS_TYPE_STRING:
149                         if (g_str_equal(key, "Source") == TRUE)
150                                 dbus_message_iter_get_basic(&value, source);
151                         else if (g_str_equal(key, "Target") == TRUE)
152                                 dbus_message_iter_get_basic(&value, target);
153                         break;
154                 case DBUS_TYPE_BYTE:
155                         if (g_str_equal(key, "Channel") == TRUE)
156                                 dbus_message_iter_get_basic(&value, channel);
157                         break;
158                 }
159
160                 dbus_message_iter_next(iter);
161         }
162
163         return 0;
164 }
165
166 static struct obc_session *find_session(const char *path)
167 {
168         GSList *l;
169 #ifdef __TIZEN_PATCH__
170         if(!path)
171                 return NULL;
172 #endif
173         for (l = sessions; l; l = l->next) {
174                 struct obc_session *session = l->data;
175
176                 if (g_strcmp0(obc_session_get_path(session), path) == 0)
177                         return session;
178         }
179
180         return NULL;
181 }
182
183 static DBusMessage *create_session(DBusConnection *connection,
184                                         DBusMessage *message, void *user_data)
185 {
186         DBusMessageIter iter, dict;
187         struct obc_session *session;
188         struct send_data *data;
189         const char *source = NULL, *dest = NULL, *target = NULL;
190         uint8_t channel = 0;
191
192         dbus_message_iter_init(message, &iter);
193         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
194                 return g_dbus_create_error(message,
195                                 ERROR_INTERFACE ".InvalidArguments", NULL);
196
197         dbus_message_iter_get_basic(&iter, &dest);
198         dbus_message_iter_next(&iter);
199
200         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
201                 return g_dbus_create_error(message,
202                                 ERROR_INTERFACE ".InvalidArguments", NULL);
203
204         dbus_message_iter_recurse(&iter, &dict);
205
206         parse_device_dict(&dict, &source, &target, &channel);
207         if (dest == NULL || target == NULL)
208                 return g_dbus_create_error(message,
209                                 ERROR_INTERFACE ".InvalidArguments", NULL);
210
211         data = g_try_malloc0(sizeof(*data));
212         if (data == NULL)
213                 return g_dbus_create_error(message,
214                                 ERROR_INTERFACE ".Error.NoMemory", NULL);
215
216         data->connection = dbus_connection_ref(connection);
217         data->message = dbus_message_ref(message);
218
219         session = obc_session_create(source, dest, target, channel,
220                                         dbus_message_get_sender(message),
221                                         create_callback, data);
222         if (session != NULL) {
223                 return NULL;
224         }
225
226         dbus_message_unref(data->message);
227         dbus_connection_unref(data->connection);
228         g_free(data);
229
230         return g_dbus_create_error(message, ERROR_INTERFACE ".Failed", NULL);
231 }
232
233 static DBusMessage *remove_session(DBusConnection *connection,
234                                 DBusMessage *message, void *user_data)
235 {
236         struct obc_session *session;
237         const char *sender, *path;
238
239         if (dbus_message_get_args(message, NULL,
240                         DBUS_TYPE_OBJECT_PATH, &path,
241                         DBUS_TYPE_INVALID) == FALSE)
242                 return g_dbus_create_error(message,
243                                 ERROR_INTERFACE ".InvalidArguments", NULL);
244
245         session = find_session(path);
246         if (session == NULL)
247                 return g_dbus_create_error(message,
248                                 ERROR_INTERFACE ".InvalidArguments", NULL);
249
250         sender = dbus_message_get_sender(message);
251         if (g_str_equal(sender, obc_session_get_owner(session)) == FALSE)
252                 return g_dbus_create_error(message,
253                                 ERROR_INTERFACE ".NotAuthorized",
254                                 "Not Authorized");
255
256         release_session(session);
257
258         return dbus_message_new_method_return(message);
259 }
260
261 static const GDBusMethodTable client_methods[] = {
262         { GDBUS_ASYNC_METHOD("CreateSession",
263                         GDBUS_ARGS({ "destination", "s" }, { "args", "a{sv}" }),
264                         GDBUS_ARGS({ "session", "o" }), create_session) },
265         { GDBUS_ASYNC_METHOD("RemoveSession",
266                         GDBUS_ARGS({ "session", "o" }), NULL, remove_session) },
267         { }
268 };
269
270 static DBusConnection *conn = NULL;
271
272 static struct obc_module {
273         const char *name;
274         int (*init) (void);
275         void (*exit) (void);
276 } modules[] = {
277         { "bluetooth", bluetooth_init, bluetooth_exit },
278         { "opp", opp_init, opp_exit },
279         { "ftp", ftp_init, ftp_exit },
280         { "pbap", pbap_init, pbap_exit },
281         { "sync", sync_init, sync_exit },
282         { "map", map_init, map_exit },
283 #ifdef __TIZEN_PATCH__
284         { "mns", mns_init, mns_exit },
285 #endif
286         { }
287 };
288
289 int client_manager_init(void)
290 {
291         DBusError derr;
292         struct obc_module *module;
293
294         dbus_error_init(&derr);
295
296         conn = manager_dbus_get_connection();
297         if (conn == NULL) {
298                 error("Can't get client D-Bus connection");
299                 return -1;
300         }
301
302         if (g_dbus_register_interface(conn, CLIENT_PATH, CLIENT_INTERFACE,
303                                                 client_methods, NULL, NULL,
304                                                         NULL, NULL) == FALSE) {
305                 error("Can't register client interface");
306                 dbus_connection_unref(conn);
307                 conn = NULL;
308                 return -1;
309         }
310
311         for (module = modules; module && module->init; module++) {
312                 if (module->init() < 0)
313                         continue;
314
315                 DBG("Module %s loaded", module->name);
316         }
317
318         return 0;
319 }
320
321 void client_manager_exit(void)
322 {
323         struct obc_module *module;
324
325         if (conn == NULL)
326                 return;
327
328         for (module = modules; module && module->exit; module++)
329                 module->exit();
330
331         g_dbus_unregister_interface(conn, CLIENT_PATH, CLIENT_INTERFACE);
332
333         dbus_connection_unref(conn);
334 }