7269d42328fe602464f83e1d62dac3fad31d65b2
[platform/core/connectivity/bluetooth-frwk.git] / capi / bluetooth-obex.c
1 /*
2 * Bluetooth-Frwk-NG
3 *
4 * Copyright (c) 2013-2014 Intel Corporation.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *              http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <glib.h>
24 #include <gio/gio.h>
25 #include <dirent.h>
26 #include <dbus/dbus.h>
27 #include <gio/gunixfdlist.h>
28 #include <string.h>
29
30 #include "bluetooth.h"
31 #include "obex.h"
32 #include "common.h"
33 #include "bluetooth-service.h"
34 #include "bluez.h"
35
36 #define OBEX_LIB_SERVICE "org.obex.lib"
37 #define AGENT_OBJECT_PATH "/org/obex/lib"
38
39 #define OBEX_ERROR_INTERFACE "org.bluez.obex.Error"
40
41 #define ADDRESS_LEN 20
42 static char pushing_address[ADDRESS_LEN];
43
44 typedef enum {
45         BT_OPP_TRANSFER_UNKNOWN = 0x0,
46         BT_OPP_TRANSFER_QUEUED,
47         BT_OPP_TRANSFER_ACTIVE,
48         BT_OPP_TRANSFER_COMPLETED,
49         BT_OPP_TRANSFER_CANCELED,
50         BT_OPP_TRANSFER_ERROR,
51 } bt_opp_transfer_state_e;
52
53 typedef void (*bt_opp_server_push_file_requested_cb)(
54                         const char *remote_address,
55                         const char *name,
56                         uint64_t size,
57                         void *user_data);
58
59 typedef void (*bt_opp_transfer_state_cb)(
60                         int transfer_id,
61                         bt_opp_transfer_state_e state,
62                         const char *name,
63                         uint64_t size,
64                         unsigned char percent,
65                         void *user_data);
66
67 typedef enum {
68         BT_OPP_PUSH_ACCETPED = 0,
69         BT_OPP_PUSH_RETRY,
70         BT_OPP_PUSH_FAILED,
71         BT_OPP_PUSH_REFUSED,
72         BT_OPP_PUSH_TIMEOUT,
73         BT_OPP_PUSH_NO_SERVICE
74 } push_state_e;
75
76 typedef void (*bt_opp_client_push_responded_new_cb)(
77                         const char *remote_address,
78                         push_state_e state,
79                         void *user_data);
80
81 static struct {
82         char *root_folder;
83         char *pending_name;
84         char *pending_transfer_path;
85         bt_opp_server_push_file_requested_cb requested_cb;
86         void *user_data;
87         int pending_transfer_id;
88         GDBusMethodInvocation *pending_invocation;
89 } opp_server;
90
91 struct opp_transfer_state_cb_node {
92         bt_opp_transfer_state_cb cb;
93         void *user_data;
94 };
95
96 static gboolean is_client_register;
97 static gboolean is_server_register;
98 static void *opp_client_data;
99
100 static guint bluetooth_ext_agent_id;
101
102 static struct opp_transfer_state_cb_node *opp_transfer_state_node;
103
104 static void bt_opp_server_transfer_state_cb(bt_opp_transfer_state_e state,
105                                 const char *name, uint64_t size,
106                                 unsigned char percent, void *user_data);
107
108 static void bt_opp_client_transfer_state_cb(unsigned int id,
109                         bt_opp_transfer_state_e state, const char *address,
110                         const char *name, uint64_t size,
111                         unsigned char percent, void *user_data);
112
113 static int bt_opp_server_reject_request(void);
114
115 static int bt_device_get_privileges(const char *remote_address)
116 {
117         int user_privilieges;
118
119         DBG("address = %s", remote_address);
120
121         user_privilieges = comms_bluetooth_get_user_privileges_sync(
122                                                         remote_address);
123
124         return user_privilieges;
125 }
126
127 static GDBusNodeInfo *introspection_data;
128
129 static const gchar introspection_xml[] =
130         "<node>"
131         "  <interface name='org.bluez.obex.Agent1'>"
132         "    <method name='Release'>"
133         "    </method>"
134         "    <method name='AuthorizePush'>"
135         "      <arg type='s' name='address' direction='in'/>"
136         "      <arg type='s' name='name' direction='in'/>"
137         "      <arg type='s' name='path' direction='in'/>"
138         "      <arg type='t' name='size' direction='in'/>"
139         "      <arg type='i' name='transfer_id' direction='in'/>"
140         "      <arg type='s' direction='out'/>"
141         "    </method>"
142         "    <method name='Cancel'>"
143         "    </method>"
144         "  </interface>"
145         "</node>";
146
147 static void handle_cancel(GDBusMethodInvocation *invocation)
148 {
149         DBG("");
150
151         g_dbus_method_invocation_return_value(invocation, NULL);
152 }
153
154 static void handle_release(GDBusMethodInvocation *invocation)
155 {
156         DBG("");
157
158         g_dbus_method_invocation_return_value(invocation, NULL);
159 }
160
161 static void bt_opp_manager_service_watch(
162                         gchar *address, gchar *name,
163                         guint64 size, guint id,
164                         guint state, double percent,
165                         void *user_data)
166 {
167         DBG("transfer_id = %d, state = %d", id, state);
168
169         if (id >= 10000)
170                 bt_opp_server_transfer_state_cb(state, name, size,
171                         percent, opp_server.user_data);
172         else
173                 bt_opp_client_transfer_state_cb(id, state,
174                         address, name, size, percent, opp_client_data);
175 }
176
177 static void handle_method_call(GDBusConnection *connection,
178                                 const gchar *sender,
179                                 const gchar *object_path,
180                                 const gchar *interface_name,
181                                 const gchar *method_name,
182                                 GVariant *parameters,
183                                 GDBusMethodInvocation *invocation,
184                                 gpointer user_data)
185 {
186
187         DBG("%s", method_name);
188
189         if (g_strcmp0(method_name, "Release") == 0) {
190                 handle_release(invocation);
191                 return;
192         } else if (g_strcmp0(method_name, "AuthorizePush") == 0) {
193                 gchar *address, *name, *transfer_path;
194                 gchar *device_name = NULL;
195                 bluez_adapter_t *adapter;
196                 bluez_device_t *device;
197                 int transfer_id;
198                 guint64 size;
199                 int privilieges;
200
201                 opp_server.pending_invocation = invocation;
202
203                 g_variant_get(parameters, "(sssti)", &address,
204                                 &name, &transfer_path, &size, &transfer_id);
205
206                 privilieges = bt_device_get_privileges(address);
207                 if (privilieges == 0) {
208                         DBG("user not privilieges to pair and use");
209                         /*todo: This point will check if Cynara allow user
210                         use the remote device
211                         if ok, return BT_SUCCESS.
212                         */
213                         bt_opp_server_reject_request();
214                         return;
215                 }
216
217                 adapter = bluez_adapter_get_adapter(DEFAULT_ADAPTER_NAME);
218                 device = bluez_adapter_get_device_by_address(adapter,
219                                                                 address);
220                 if (device)
221                         device_name = bluez_device_get_property_alias(device);
222
223                 opp_server.pending_name = g_strdup(name);
224                 opp_server.pending_transfer_path = g_strdup(transfer_path);
225                 opp_server.pending_transfer_id = transfer_id;
226
227                 if (opp_server.requested_cb)
228                         opp_server.requested_cb((const char *) device_name,
229                                         (const char *) name,
230                                         size, opp_server.user_data);
231
232                 g_free(name);
233                 g_free(address);
234                 return;
235         } else if (g_strcmp0(method_name, "Cancel") == 0) {
236                 handle_cancel(invocation);
237
238                 return;
239         }
240 }
241
242 static const GDBusInterfaceVTable interface_handle = {
243         handle_method_call,
244         NULL,
245         NULL
246 };
247
248 static GDBusConnection *conn;
249 static guint bluetooth_opp_agent_id;
250
251 static GDBusConnection *get_system_dbus_connect(void)
252 {
253         GError *error = NULL;
254
255         if (conn != NULL)
256                 return conn;
257
258         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
259         if (conn == NULL) {
260                 DBG("%s", error->message);
261
262                 g_error_free(error);
263
264                 return NULL;
265         }
266
267         return conn;
268 }
269
270 static void release_dbus_connection(void)
271 {
272         g_object_unref(conn);
273         conn = NULL;
274 }
275
276 static void release_name_on_dbus(const char *name)
277 {
278         GVariant *ret;
279         guint32 request_name_reply;
280         GError *error = NULL;
281
282         if (bluetooth_opp_agent_id)
283                 return;
284
285         if (bluetooth_ext_agent_id)
286                 return;
287
288         ret = g_dbus_connection_call_sync(conn, "org.freedesktop.DBus",
289                         "/org/freedesktop/DBus", "org.freedesktop.DBus",
290                         "ReleaseName", g_variant_new("(s)", name),
291                         G_VARIANT_TYPE("(u)"), G_DBUS_CALL_FLAGS_NONE,
292                         -1, NULL, &error);
293         if (ret == NULL) {
294                 WARN("%s", error->message);
295                 return;
296         }
297
298         g_variant_get(ret, "(u)", &request_name_reply);
299         g_variant_unref(ret);
300
301         if (request_name_reply != 1) {
302                 WARN("Unexpected reply");
303                 return;
304         }
305
306         release_dbus_connection();
307
308         return;
309 }
310
311 static int request_name_on_dbus(const char *name)
312 {
313         GDBusConnection *connection;
314         GVariant *ret;
315         guint32 request_name_reply;
316         GError *error = NULL;
317
318         if (bluetooth_opp_agent_id)
319                 return 0;
320
321         connection = get_system_dbus_connect();
322         if (connection == NULL)
323                 return -1;
324
325         ret = g_dbus_connection_call_sync(connection, "org.freedesktop.DBus",
326                         "/org/freedesktop/DBus", "org.freedesktop.DBus",
327                         "RequestName", g_variant_new("(su)", name,
328                                 G_BUS_NAME_OWNER_FLAGS_NONE),
329                         G_VARIANT_TYPE("(u)"), G_DBUS_CALL_FLAGS_NONE,
330                         -1, NULL, &error);
331         if (ret == NULL) {
332                 WARN("%s", error->message);
333                 g_error_free(error);
334
335                 goto failed;
336         }
337
338         g_variant_get(ret, "(u)", &request_name_reply);
339         g_variant_unref(ret);
340
341         /* RequestName will return the uint32 value:
342          * 1: DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER
343          * 2: BUS_REQUEST_NAME_REPLY_IN_QUEUE
344          * 3: DBUS_REQUEST_NAME_REPLY_EXISTS
345          * 4: DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER
346          * Also see dbus doc
347          */
348         if (request_name_reply == DBUS_REQUEST_NAME_REPLY_IN_QUEUE
349                 || request_name_reply == DBUS_REQUEST_NAME_REPLY_EXISTS
350                 || request_name_reply ==
351                                 DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER) {
352                 bluetooth_ext_agent_id = 1;
353                 return 0;
354         }
355
356         if (request_name_reply != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
357                 DBG("Lost name");
358
359                 release_name_on_dbus(name);
360
361                 goto failed;
362         }
363
364         if (bluetooth_ext_agent_id > 0)
365                 bluetooth_ext_agent_id = 0;
366
367         return 0;
368 failed:
369         g_object_unref(connection);
370
371         return -1;
372 }
373
374 static void destroy_opp_object(void)
375 {
376         DBG("bluetooth_opp_agent_id = %d", bluetooth_opp_agent_id);
377
378         if (is_client_register || is_server_register)
379                 return;
380
381         if (bluetooth_opp_agent_id > 0) {
382                 g_dbus_connection_unregister_object(conn,
383                                         bluetooth_opp_agent_id);
384                 bluetooth_opp_agent_id = 0;
385                 release_name_on_dbus(OBEX_LIB_SERVICE);
386         }
387
388         return;
389 }
390
391 static void destroy_opp_agent(void)
392 {
393         DBG("bluetooth_opp_agent_id = %d", bluetooth_opp_agent_id);
394
395         destroy_opp_object();
396
397         comms_bluetooth_unregister_opp_agent(
398                                 AGENT_OBJECT_PATH, NULL, NULL);
399
400         return;
401 }
402
403 static int register_opp_object(void)
404 {
405         int ret;
406
407         DBG("");
408
409         if (bluetooth_opp_agent_id)
410                 return BT_SUCCESS;
411
412         introspection_data =
413                 g_dbus_node_info_new_for_xml(introspection_xml, NULL);
414
415         ret = request_name_on_dbus(OBEX_LIB_SERVICE);
416         if (ret != 0)
417                 return BT_ERROR_OPERATION_FAILED;
418
419         DBG("%s requested success", OBEX_LIB_SERVICE);
420
421         bluetooth_opp_agent_id = g_dbus_connection_register_object(conn,
422                                         AGENT_OBJECT_PATH,
423                                         introspection_data-> interfaces[0],
424                                         &interface_handle, NULL, NULL, NULL);
425
426         DBG("bluetooth_opp_agent_id = %d", bluetooth_opp_agent_id);
427
428         if (bluetooth_opp_agent_id == 0)
429                 return BT_ERROR_OPERATION_FAILED;
430
431         return BT_SUCCESS;
432 }
433
434 static int register_opp_agent(void)
435 {
436         int ret;
437
438         DBG("");
439
440         ret = register_opp_object();
441
442         if (ret == BT_SUCCESS) {
443                 if (is_server_register)
444                         return BT_SUCCESS;
445         } else
446                 return BT_ERROR_OPERATION_FAILED;
447
448         ret = comms_bluetooth_register_opp_agent_sync(
449                                                 AGENT_OBJECT_PATH, NULL);
450
451         DBG("ret = %d", ret);
452
453         if (ret != BT_SUCCESS) {
454                 is_server_register = FALSE;
455                 destroy_opp_agent();
456                 return BT_ERROR_OPERATION_FAILED;
457         }
458
459         return BT_SUCCESS;
460 }
461
462 static int bt_opp_register_server(const char *dir,
463                         bt_opp_server_push_file_requested_cb push_requested_cb,
464                         void *user_data)
465 {
466         int ret;
467
468         if (dir == NULL || push_requested_cb == NULL)
469                 return BT_ERROR_INVALID_PARAMETER;
470
471         if (!g_file_test(dir, G_FILE_TEST_IS_DIR)) {
472                 ERROR("%s is not valid directory", dir);
473                 return BT_ERROR_INVALID_PARAMETER;
474         }
475
476         ret = register_opp_agent();
477         if (ret != BT_SUCCESS)
478                 return ret;
479
480         is_server_register = TRUE;
481
482         opp_manager_set_service_watch(bt_opp_manager_service_watch,
483                                                         NULL);
484
485         /* TODO: Do we need to check the dir privilege? */
486
487         opp_server.root_folder = g_strdup(dir);
488         opp_server.requested_cb = push_requested_cb;
489         opp_server.user_data = user_data;
490
491         return BT_SUCCESS;
492 }
493
494 static int bt_opp_unregister_server(void)
495 {
496         /* TODO: unregister agent */
497         g_free(opp_server.root_folder);
498         opp_server.root_folder = NULL;
499
500         opp_server.requested_cb = NULL;
501         opp_server.user_data = NULL;
502
503         is_server_register = FALSE;
504         destroy_opp_agent();
505
506         if (is_client_register)
507                 return 0;
508
509         opp_manager_remove_service_watch();
510
511         return 0;
512 }
513
514 int bt_opp_set_transfers_state_cb(bt_opp_transfer_state_cb cb, void *user_data)
515 {
516         struct opp_transfer_state_cb_node *state_node;
517
518         DBG("");
519
520         if (cb == NULL)
521                 return BT_ERROR_INVALID_PARAMETER;
522
523         if (opp_transfer_state_node) {
524                 DBG("transfer state callback already set.");
525                 return BT_ERROR_ALREADY_DONE;
526         }
527
528         state_node = g_new0(struct opp_transfer_state_cb_node, 1);
529         if (state_node == NULL) {
530                 ERROR("no memory.");
531                 return BT_ERROR_OUT_OF_MEMORY;
532         }
533
534         state_node->cb = cb;
535         state_node->user_data = user_data;
536
537         opp_transfer_state_node = state_node;
538
539         return BT_SUCCESS;
540 }
541
542 void bt_opp_clear_transfers_state_cb(void)
543 {
544         DBG("");
545
546         if (!opp_transfer_state_node)
547                 return;
548
549         g_free(opp_transfer_state_node);
550         opp_transfer_state_node = NULL;
551 }
552
553 int bt_opp_server_accept_request(const char *name, void *user_data,
554                                                         int *transfer_id)
555 {
556         GDBusMethodInvocation *invocation;
557         char *n, *file_name;
558
559         invocation = opp_server.pending_invocation;
560
561         if (invocation == NULL) {
562                 ERROR("Can't find invocation");
563                 return BT_ERROR_OPERATION_FAILED;
564         }
565
566         n = (name != NULL) ? (char *) name : opp_server.pending_name;
567
568         if (opp_server.root_folder) {
569                 file_name = g_build_filename(opp_server.root_folder, n, NULL);
570                 g_dbus_method_invocation_return_value(invocation,
571                                         g_variant_new("(s)", file_name));
572                 g_free(file_name);
573         } else
574                 g_dbus_method_invocation_return_value(invocation,
575                                                 g_variant_new("(s)", n));
576
577         opp_server.pending_invocation = NULL;
578         opp_server.user_data = user_data;
579
580         comms_bluetooth_opp_add_notify(opp_server.pending_transfer_path,
581                                                         NULL, NULL);
582
583         *transfer_id = opp_server.pending_transfer_id;
584
585         g_free(opp_server.pending_transfer_path);
586         opp_server.pending_transfer_path = NULL;
587         g_free(opp_server.pending_name);
588         opp_server.pending_name = NULL;
589
590         return BT_SUCCESS;
591 }
592
593 int bt_opp_server_reject_request(void)
594 {
595         if (opp_server.pending_invocation) {
596                 g_dbus_method_invocation_return_dbus_error(
597                                         opp_server.pending_invocation,
598                                         OBEX_ERROR_INTERFACE ".Rejected",
599                                         "RejectByUser");
600
601                 opp_server.pending_invocation = NULL;
602         }
603
604         opp_server.user_data = NULL;
605         g_free(opp_server.pending_transfer_path);
606         opp_server.pending_transfer_path = NULL;
607         g_free(opp_server.pending_name);
608         opp_server.pending_name = NULL;
609
610         return 0;
611 }
612
613 int bt_opp_transfer_cancel(int transfer_id)
614 {
615         comms_bluetooth_opp_cancel_transfer(transfer_id, NULL, NULL);
616         return BT_SUCCESS;
617 }
618
619 int bt_opp_server_set_destination(const char *dir)
620 {
621         if (dir == NULL)
622                 return BT_ERROR_INVALID_PARAMETER;
623
624         if (opp_server.root_folder != NULL)
625                 g_free(opp_server.root_folder);
626
627         opp_server.root_folder = g_strdup(dir);
628
629         return BT_SUCCESS;
630 }
631
632 struct opp_push_data{
633         char *file_name;
634         bt_opp_client_push_responded_cb responded_cb;
635         void *responded_data;
636         bt_opp_transfer_state_cb transfer_state_cb;
637         void *transfer_data;
638 };
639
640 int bt_opp_client_push_file(const char *remote_address)
641 {
642         if (remote_address == NULL)
643                 return BT_ERROR_INVALID_PARAMETER;
644
645         return comms_bluetooth_opp_send_file(remote_address,
646                         AGENT_OBJECT_PATH, NULL, NULL);
647 }
648
649 /* Deprecate OPP APIs.
650  * Always implement using NEW OPP APIs*/
651 struct opp_server_push_cb_node {
652         bt_opp_server_push_requested_cb callback;
653         void *user_data;
654 };
655
656 struct opp_server_connection_requested_cb {
657         bt_opp_server_connection_requested_cb callback;
658         void *user_data;
659 };
660
661 struct opp_server_push_cb_node *opp_server_push_node;
662 struct opp_server_connection_requested_cb *opp_server_conn_req_node;
663 static bt_opp_server_transfer_progress_cb bt_transfer_progress_cb;
664 static bt_opp_server_transfer_finished_cb bt_transfer_finished_cb;
665 static bt_opp_client_push_progress_cb bt_progress_cb;
666 static bt_opp_client_push_responded_cb bt_push_responded_cb;
667 static bt_opp_client_push_finished_cb bt_finished_cb;
668
669 void server_push_requested_cb(const char *remote_address, const char *name,
670                                         uint64_t size, void *user_data)
671 {
672         if (opp_server_push_node)
673                 opp_server_push_node->callback(name, size,
674                                 opp_server_push_node->user_data);
675 }
676
677 void server_connect_requested_cb(const char *remote_address, const char *name,
678                                         uint64_t size, void *user_data)
679 {
680         if (opp_server_conn_req_node)
681                 opp_server_conn_req_node->callback(remote_address,
682                                 opp_server_conn_req_node->user_data);
683 }
684
685 int bt_opp_server_initialize(const char *destination,
686                         bt_opp_server_push_requested_cb push_requested_cb,
687                         void *user_data)
688 {
689         int ret;
690
691         if (!destination || !push_requested_cb)
692                 return BT_ERROR_INVALID_PARAMETER;
693
694         if (opp_server_push_node) {
695                 ERROR("Already registered");
696                 return BT_ERROR_OPERATION_FAILED;
697         }
698
699         opp_server_push_node = g_new0(struct opp_server_push_cb_node, 1);
700         if (opp_server_push_node == NULL) {
701                 ERROR("no memroy");
702                 return BT_ERROR_OUT_OF_MEMORY;
703         }
704
705         ret = bt_opp_register_server(destination,
706                                 server_push_requested_cb, NULL);
707         if (ret != BT_SUCCESS) {
708                 g_free(opp_server_push_node);
709                 opp_server_push_node = NULL;
710                 return BT_ERROR_OPERATION_FAILED;
711         }
712
713         opp_server_push_node->callback = push_requested_cb;
714         opp_server_push_node->user_data = user_data;
715
716         return ret;
717 }
718
719 int bt_opp_server_initialize_by_connection_request(const char *destination,
720                 bt_opp_server_connection_requested_cb connection_requested_cb,
721                 void *user_data)
722 {
723         int ret;
724
725         if (!destination || !connection_requested_cb)
726                 return BT_ERROR_INVALID_PARAMETER;
727
728         if (opp_server_conn_req_node) {
729                 ERROR("Already registered");
730                 return BT_ERROR_OPERATION_FAILED;
731         }
732
733         opp_server_conn_req_node =
734                         g_new0(struct opp_server_connection_requested_cb, 1);
735         if (opp_server_conn_req_node == NULL) {
736                 ERROR("no memroy");
737                 return BT_ERROR_OUT_OF_MEMORY;
738         }
739
740         ret = bt_opp_register_server(destination,
741                                 server_connect_requested_cb, NULL);
742         if (ret != BT_SUCCESS) {
743                 g_free(opp_server_conn_req_node);
744                 opp_server_conn_req_node = NULL;
745                 return BT_ERROR_OPERATION_FAILED;
746         }
747
748         opp_server_conn_req_node->callback = connection_requested_cb;
749         opp_server_conn_req_node->user_data = user_data;
750
751         return ret;
752 }
753
754 int bt_opp_server_deinitialize(void)
755 {
756         if (opp_server_push_node) {
757                 g_free(opp_server_push_node);
758                 opp_server_push_node = NULL;
759         }
760
761         if (opp_server_conn_req_node) {
762                 g_free(opp_server_conn_req_node);
763                 opp_server_conn_req_node = NULL;
764         }
765
766         bt_transfer_progress_cb = NULL;
767         bt_transfer_finished_cb = NULL;
768
769         return bt_opp_unregister_server();
770 }
771
772 static void bt_opp_server_transfer_state_cb(bt_opp_transfer_state_e state,
773                                 const char *name, uint64_t size,
774                                 unsigned char percent, void *user_data)
775 {
776         if (state == BT_OPP_TRANSFER_QUEUED ||
777                         state == BT_OPP_TRANSFER_ACTIVE)
778                 bt_transfer_progress_cb(name, size, percent, user_data);
779         else if (state == BT_OPP_TRANSFER_COMPLETED)
780                 bt_transfer_finished_cb(BT_ERROR_NONE, name, size, user_data);
781         else if (state == BT_OPP_TRANSFER_ERROR || BT_OPP_TRANSFER_CANCELED)
782                 bt_transfer_finished_cb(BT_ERROR_CANCELLED, name, size, user_data);
783
784 }
785
786 static void bt_opp_client_transfer_state_cb(unsigned int id,
787                                 bt_opp_transfer_state_e state,
788                                 const char *address, const char *name,
789                                 uint64_t size, unsigned char percent,
790                                 void *user_data)
791 {
792         DBG("+");
793
794         if (state == BT_OPP_TRANSFER_QUEUED) {
795                 DBG("id = %d, name = %s", id, name);
796                 if (id == 0 && !g_strcmp0(name, "OBEX_TRANSFER_QUEUED")) {
797                         if (bt_push_responded_cb)
798                                 bt_push_responded_cb(BT_ERROR_NONE,
799                                                         address, user_data);
800                 } else {
801                         if (bt_progress_cb)
802                                 bt_progress_cb(name, size, percent, user_data);
803                 }
804         } else if  (state == BT_OPP_TRANSFER_ACTIVE) {
805                 if (bt_progress_cb)
806                         bt_progress_cb(name, size, percent, user_data);
807         } else if (state == BT_OPP_TRANSFER_COMPLETED) {
808                 if (bt_finished_cb)
809                         bt_finished_cb(BT_ERROR_NONE, address, user_data);
810         } else if (state == BT_OPP_TRANSFER_ERROR ||
811                         state == BT_OPP_TRANSFER_CANCELED ||
812                                         state == BT_OPP_TRANSFER_UNKNOWN) {
813                 if (bt_finished_cb)
814                         bt_finished_cb(BT_ERROR_CANCELLED, address, user_data);
815         }
816
817         DBG("-");
818 }
819
820 int bt_opp_server_accept(bt_opp_server_transfer_progress_cb progress_cb,
821                         bt_opp_server_transfer_finished_cb finished_cb,
822                         const char *name, void *user_data, int *transfer_id)
823 {
824         bt_transfer_progress_cb = progress_cb;
825         bt_transfer_finished_cb = finished_cb;
826
827         return bt_opp_server_accept_request(name, user_data, transfer_id);
828 }
829
830 int bt_opp_server_reject(void)
831 {
832         return bt_opp_server_reject_request();
833 }
834
835 int bt_opp_server_cancel_transfer(int transfer_id)
836 {
837         return bt_opp_transfer_cancel(transfer_id);
838 }
839
840 int bt_opp_client_initialize(void)
841 {
842         int ret;
843
844         ret = register_opp_object();
845         if (ret != BT_SUCCESS)
846                 return ret;
847
848         is_client_register = TRUE;
849
850         opp_manager_set_service_watch(bt_opp_manager_service_watch,
851                                                         NULL);
852         return BT_SUCCESS;
853 }
854
855 int bt_opp_client_deinitialize(void)
856 {
857         is_client_register = FALSE;
858
859         destroy_opp_object();
860
861         if (is_server_register)
862                 return BT_SUCCESS;
863
864         opp_manager_remove_service_watch();
865
866         return BT_SUCCESS;
867 }
868
869 int bt_opp_client_add_file(const char *file)
870 {
871         int ret = BT_ERROR_NONE;
872
873         DBG("+");
874
875         if (file == NULL)
876                 return BT_ERROR_INVALID_PARAMETER;
877
878         if (access(file, F_OK) != 0) {
879                 ret = BT_ERROR_INVALID_PARAMETER;
880                 DBG("ret = %d", ret);
881                 return ret;
882         }
883
884         ret = comms_bluetooth_opp_add_file(file,
885                         AGENT_OBJECT_PATH, NULL, NULL);
886
887         if (ret != BT_ERROR_NONE)
888                 return BT_ERROR_OPERATION_FAILED;
889
890         DBG("-");
891
892         return BT_ERROR_NONE;
893 }
894
895 int bt_opp_client_clear_files(void)
896 {
897         DBG("");
898
899         comms_bluetooth_opp_remove_Files(AGENT_OBJECT_PATH, NULL, NULL);
900
901         return BT_ERROR_NONE;
902 }
903
904 int bt_opp_client_push_files(const char *remote_address,
905                                 bt_opp_client_push_responded_cb responded_cb,
906                                 bt_opp_client_push_progress_cb progress_cb,
907                                 bt_opp_client_push_finished_cb finished_cb,
908                                 void *user_data)
909 {
910         int user_privilieges;
911         int ret;
912
913         if (remote_address == NULL) {
914                 DBG("address = NULL");
915                 return BT_ERROR_INVALID_PARAMETER;
916         }
917
918         DBG("");
919
920         user_privilieges = bt_device_get_privileges(remote_address);
921         if (user_privilieges == 0) {
922                  DBG("user not privilieges to pair and use");
923                 /*todo: This point will check if Cynara allow user
924                         use the remote device
925                         if ok, return BT_SUCCESS.
926                 */
927                 memset(pushing_address, 0, ADDRESS_LEN);
928                 return BT_ERROR_NOT_ENABLED;
929         }
930
931         memset(pushing_address, 0, ADDRESS_LEN);
932         strcpy(pushing_address, remote_address);
933
934         bt_push_responded_cb = responded_cb;
935         bt_progress_cb = progress_cb;
936         bt_finished_cb = finished_cb;
937         opp_client_data = user_data;
938
939         ret = bt_opp_client_push_file(remote_address);
940
941         if (ret == 1) {
942                 DBG("BT_ERROR_NOW_IN_PROGRESS");
943                 return BT_ERROR_NOW_IN_PROGRESS;
944         }
945
946         return ret;
947 }
948
949 int bt_opp_client_cancel_push(void)
950 {
951         int user_privilieges;
952
953         if (strlen(pushing_address) == 0) {
954                 DBG("not need to cancel bonding");
955                 return BT_ERROR_NOT_ENABLED;
956         }
957
958         user_privilieges = bt_device_get_privileges(pushing_address);
959         memset(pushing_address, 0, ADDRESS_LEN);
960
961         if (user_privilieges == 0) {
962                 DBG("user not privilieges to pair and use");
963                 /*todo: This point will check if Cynara allow user
964                         use the remote device
965                         if ok, return BT_SUCCESS.
966                 */
967                 return BT_ERROR_NOT_ENABLED;
968         }
969
970         comms_bluetooth_opp_cancel_transfers(NULL, NULL);
971
972         return 0;
973 }
974