Add the info dbus message of transfer cancel
[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         DBG("");
497         /* TODO: unregister agent */
498         g_free(opp_server.root_folder);
499         opp_server.root_folder = NULL;
500
501         opp_server.requested_cb = NULL;
502         opp_server.user_data = NULL;
503
504         is_server_register = FALSE;
505         destroy_opp_agent();
506
507         if (is_client_register)
508                 return 0;
509
510         opp_manager_remove_service_watch();
511
512         return 0;
513 }
514
515 int bt_opp_set_transfers_state_cb(bt_opp_transfer_state_cb cb, void *user_data)
516 {
517         struct opp_transfer_state_cb_node *state_node;
518
519         DBG("");
520
521         if (cb == NULL)
522                 return BT_ERROR_INVALID_PARAMETER;
523
524         if (opp_transfer_state_node) {
525                 DBG("transfer state callback already set.");
526                 return BT_ERROR_ALREADY_DONE;
527         }
528
529         state_node = g_new0(struct opp_transfer_state_cb_node, 1);
530         if (state_node == NULL) {
531                 ERROR("no memory.");
532                 return BT_ERROR_OUT_OF_MEMORY;
533         }
534
535         state_node->cb = cb;
536         state_node->user_data = user_data;
537
538         opp_transfer_state_node = state_node;
539
540         return BT_SUCCESS;
541 }
542
543 void bt_opp_clear_transfers_state_cb(void)
544 {
545         DBG("");
546
547         if (!opp_transfer_state_node)
548                 return;
549
550         g_free(opp_transfer_state_node);
551         opp_transfer_state_node = NULL;
552 }
553
554 int bt_opp_server_accept_request(const char *name, void *user_data,
555                                                         int *transfer_id)
556 {
557         GDBusMethodInvocation *invocation;
558         char *n, *file_name;
559
560         invocation = opp_server.pending_invocation;
561
562         if (invocation == NULL) {
563                 ERROR("Can't find invocation");
564                 return BT_ERROR_OPERATION_FAILED;
565         }
566
567         n = (name != NULL) ? (char *) name : opp_server.pending_name;
568
569         if (opp_server.root_folder) {
570                 file_name = g_build_filename(opp_server.root_folder, n, NULL);
571                 g_dbus_method_invocation_return_value(invocation,
572                                         g_variant_new("(s)", file_name));
573                 g_free(file_name);
574         } else
575                 g_dbus_method_invocation_return_value(invocation,
576                                                 g_variant_new("(s)", n));
577
578         opp_server.pending_invocation = NULL;
579         opp_server.user_data = user_data;
580
581         comms_bluetooth_opp_add_notify(opp_server.pending_transfer_path,
582                                                         NULL, NULL);
583
584         *transfer_id = opp_server.pending_transfer_id;
585
586         g_free(opp_server.pending_transfer_path);
587         opp_server.pending_transfer_path = NULL;
588         g_free(opp_server.pending_name);
589         opp_server.pending_name = NULL;
590
591         return BT_SUCCESS;
592 }
593
594 int bt_opp_server_reject_request(void)
595 {
596         if (opp_server.pending_invocation) {
597                 g_dbus_method_invocation_return_dbus_error(
598                                         opp_server.pending_invocation,
599                                         OBEX_ERROR_INTERFACE ".Rejected",
600                                         "RejectByUser");
601
602                 opp_server.pending_invocation = NULL;
603         }
604
605         opp_server.user_data = NULL;
606         g_free(opp_server.pending_transfer_path);
607         opp_server.pending_transfer_path = NULL;
608         g_free(opp_server.pending_name);
609         opp_server.pending_name = NULL;
610
611         return 0;
612 }
613
614 int bt_opp_transfer_cancel(int transfer_id)
615 {
616         comms_bluetooth_opp_cancel_transfer(transfer_id, NULL, NULL);
617         return BT_SUCCESS;
618 }
619
620 int bt_opp_server_set_destination(const char *dir)
621 {
622         if (dir == NULL)
623                 return BT_ERROR_INVALID_PARAMETER;
624
625         if (opp_server.root_folder != NULL)
626                 g_free(opp_server.root_folder);
627
628         opp_server.root_folder = g_strdup(dir);
629
630         return BT_SUCCESS;
631 }
632
633 struct opp_push_data{
634         char *file_name;
635         bt_opp_client_push_responded_cb responded_cb;
636         void *responded_data;
637         bt_opp_transfer_state_cb transfer_state_cb;
638         void *transfer_data;
639 };
640
641 int bt_opp_client_push_file(const char *remote_address)
642 {
643         if (remote_address == NULL)
644                 return BT_ERROR_INVALID_PARAMETER;
645
646         return comms_bluetooth_opp_send_file(remote_address,
647                         AGENT_OBJECT_PATH, NULL, NULL);
648 }
649
650 /* Deprecate OPP APIs.
651  * Always implement using NEW OPP APIs*/
652 struct opp_server_push_cb_node {
653         bt_opp_server_push_requested_cb callback;
654         void *user_data;
655 };
656
657 struct opp_server_connection_requested_cb {
658         bt_opp_server_connection_requested_cb callback;
659         void *user_data;
660 };
661
662 struct opp_server_push_cb_node *opp_server_push_node;
663 struct opp_server_connection_requested_cb *opp_server_conn_req_node;
664 static bt_opp_server_transfer_progress_cb bt_transfer_progress_cb;
665 static bt_opp_server_transfer_finished_cb bt_transfer_finished_cb;
666 static bt_opp_client_push_progress_cb bt_progress_cb;
667 static bt_opp_client_push_responded_cb bt_push_responded_cb;
668 static bt_opp_client_push_finished_cb bt_finished_cb;
669
670 void server_push_requested_cb(const char *remote_address, const char *name,
671                                         uint64_t size, void *user_data)
672 {
673         if (opp_server_push_node)
674                 opp_server_push_node->callback(name, size,
675                                 opp_server_push_node->user_data);
676 }
677
678 void server_connect_requested_cb(const char *remote_address, const char *name,
679                                         uint64_t size, void *user_data)
680 {
681         if (opp_server_conn_req_node)
682                 opp_server_conn_req_node->callback(remote_address,
683                                 opp_server_conn_req_node->user_data);
684 }
685
686 int bt_opp_server_initialize(const char *destination,
687                         bt_opp_server_push_requested_cb push_requested_cb,
688                         void *user_data)
689 {
690         int ret;
691
692         if (!destination || !push_requested_cb)
693                 return BT_ERROR_INVALID_PARAMETER;
694
695         if (opp_server_push_node) {
696                 ERROR("Already registered");
697                 return BT_ERROR_OPERATION_FAILED;
698         }
699
700         opp_server_push_node = g_new0(struct opp_server_push_cb_node, 1);
701         if (opp_server_push_node == NULL) {
702                 ERROR("no memroy");
703                 return BT_ERROR_OUT_OF_MEMORY;
704         }
705
706         ret = bt_opp_register_server(destination,
707                                 server_push_requested_cb, NULL);
708         if (ret != BT_SUCCESS) {
709                 g_free(opp_server_push_node);
710                 opp_server_push_node = NULL;
711                 return BT_ERROR_OPERATION_FAILED;
712         }
713
714         opp_server_push_node->callback = push_requested_cb;
715         opp_server_push_node->user_data = user_data;
716
717         return ret;
718 }
719
720 int bt_opp_server_initialize_by_connection_request(const char *destination,
721                 bt_opp_server_connection_requested_cb connection_requested_cb,
722                 void *user_data)
723 {
724         int ret;
725
726         if (!destination || !connection_requested_cb)
727                 return BT_ERROR_INVALID_PARAMETER;
728
729         if (opp_server_conn_req_node) {
730                 ERROR("Already registered");
731                 return BT_ERROR_OPERATION_FAILED;
732         }
733
734         opp_server_conn_req_node =
735                         g_new0(struct opp_server_connection_requested_cb, 1);
736         if (opp_server_conn_req_node == NULL) {
737                 ERROR("no memroy");
738                 return BT_ERROR_OUT_OF_MEMORY;
739         }
740
741         ret = bt_opp_register_server(destination,
742                                 server_connect_requested_cb, NULL);
743         if (ret != BT_SUCCESS) {
744                 g_free(opp_server_conn_req_node);
745                 opp_server_conn_req_node = NULL;
746                 return BT_ERROR_OPERATION_FAILED;
747         }
748
749         opp_server_conn_req_node->callback = connection_requested_cb;
750         opp_server_conn_req_node->user_data = user_data;
751
752         return ret;
753 }
754
755 int bt_opp_server_deinitialize(void)
756 {
757         DBG("");
758
759         if (opp_server_push_node) {
760                 g_free(opp_server_push_node);
761                 opp_server_push_node = NULL;
762         }
763
764         if (opp_server_conn_req_node) {
765                 g_free(opp_server_conn_req_node);
766                 opp_server_conn_req_node = NULL;
767         }
768
769         bt_transfer_progress_cb = NULL;
770         bt_transfer_finished_cb = NULL;
771
772         return bt_opp_unregister_server();
773 }
774
775 static void bt_opp_server_transfer_state_cb(bt_opp_transfer_state_e state,
776                                 const char *name, uint64_t size,
777                                 unsigned char percent, void *user_data)
778 {
779         if (state == BT_OPP_TRANSFER_QUEUED ||
780                         state == BT_OPP_TRANSFER_ACTIVE)
781                 bt_transfer_progress_cb(name, size, percent, user_data);
782         else if (state == BT_OPP_TRANSFER_COMPLETED)
783                 bt_transfer_finished_cb(BT_ERROR_NONE, name, size, user_data);
784         else if (state == BT_OPP_TRANSFER_ERROR || BT_OPP_TRANSFER_CANCELED)
785                 bt_transfer_finished_cb(BT_ERROR_CANCELLED, name, size, user_data);
786
787 }
788
789 static void bt_opp_client_transfer_state_cb(unsigned int id,
790                                 bt_opp_transfer_state_e state,
791                                 const char *address, const char *name,
792                                 uint64_t size, unsigned char percent,
793                                 void *user_data)
794 {
795         DBG("+");
796
797         if (state == BT_OPP_TRANSFER_QUEUED) {
798                 DBG("id = %d, name = %s", id, name);
799                 if (id == 0 && !g_strcmp0(name, "OBEX_TRANSFER_QUEUED")) {
800                         if (bt_push_responded_cb)
801                                 bt_push_responded_cb(BT_ERROR_NONE,
802                                                         address, user_data);
803                 } else {
804                         if (bt_progress_cb)
805                                 bt_progress_cb(name, size, percent, user_data);
806                 }
807         } else if  (state == BT_OPP_TRANSFER_ACTIVE) {
808                 if (bt_progress_cb)
809                         bt_progress_cb(name, size, percent, user_data);
810         } else if (state == BT_OPP_TRANSFER_COMPLETED) {
811                 if (bt_finished_cb)
812                         bt_finished_cb(BT_ERROR_NONE, address, user_data);
813         } else if (state == BT_OPP_TRANSFER_ERROR ||
814                         state == BT_OPP_TRANSFER_CANCELED ||
815                                         state == BT_OPP_TRANSFER_UNKNOWN) {
816                 if (bt_finished_cb)
817                         bt_finished_cb(BT_ERROR_CANCELLED, address, user_data);
818         }
819
820         DBG("-");
821 }
822
823 int bt_opp_server_accept(bt_opp_server_transfer_progress_cb progress_cb,
824                         bt_opp_server_transfer_finished_cb finished_cb,
825                         const char *name, void *user_data, int *transfer_id)
826 {
827         bt_transfer_progress_cb = progress_cb;
828         bt_transfer_finished_cb = finished_cb;
829
830         return bt_opp_server_accept_request(name, user_data, transfer_id);
831 }
832
833 int bt_opp_server_reject(void)
834 {
835         return bt_opp_server_reject_request();
836 }
837
838 int bt_opp_server_cancel_transfer(int transfer_id)
839 {
840         return bt_opp_transfer_cancel(transfer_id);
841 }
842
843 int bt_opp_client_initialize(void)
844 {
845         int ret;
846
847         ret = register_opp_object();
848         if (ret != BT_SUCCESS)
849                 return ret;
850
851         is_client_register = TRUE;
852
853         opp_manager_set_service_watch(bt_opp_manager_service_watch,
854                                                         NULL);
855         return BT_SUCCESS;
856 }
857
858 int bt_opp_client_deinitialize(void)
859 {
860         is_client_register = FALSE;
861
862         destroy_opp_object();
863
864         if (is_server_register)
865                 return BT_SUCCESS;
866
867         opp_manager_remove_service_watch();
868
869         return BT_SUCCESS;
870 }
871
872 int bt_opp_client_add_file(const char *file)
873 {
874         int ret = BT_ERROR_NONE;
875
876         DBG("+");
877
878         if (file == NULL)
879                 return BT_ERROR_INVALID_PARAMETER;
880
881         if (access(file, F_OK) != 0) {
882                 ret = BT_ERROR_INVALID_PARAMETER;
883                 DBG("ret = %d", ret);
884                 return ret;
885         }
886
887         ret = comms_bluetooth_opp_add_file(file,
888                         AGENT_OBJECT_PATH, NULL, NULL);
889
890         if (ret != BT_ERROR_NONE)
891                 return BT_ERROR_OPERATION_FAILED;
892
893         DBG("-");
894
895         return BT_ERROR_NONE;
896 }
897
898 int bt_opp_client_clear_files(void)
899 {
900         DBG("");
901
902         comms_bluetooth_opp_remove_Files(AGENT_OBJECT_PATH, NULL, NULL);
903
904         return BT_ERROR_NONE;
905 }
906
907 int bt_opp_client_push_files(const char *remote_address,
908                                 bt_opp_client_push_responded_cb responded_cb,
909                                 bt_opp_client_push_progress_cb progress_cb,
910                                 bt_opp_client_push_finished_cb finished_cb,
911                                 void *user_data)
912 {
913         int user_privilieges;
914         int ret;
915
916         if (remote_address == NULL) {
917                 DBG("address = NULL");
918                 return BT_ERROR_INVALID_PARAMETER;
919         }
920
921         DBG("");
922
923         user_privilieges = bt_device_get_privileges(remote_address);
924         if (user_privilieges == 0) {
925                  DBG("user not privilieges to pair and use");
926                 /*todo: This point will check if Cynara allow user
927                         use the remote device
928                         if ok, return BT_SUCCESS.
929                 */
930                 memset(pushing_address, 0, ADDRESS_LEN);
931                 return BT_ERROR_NOT_ENABLED;
932         }
933
934         memset(pushing_address, 0, ADDRESS_LEN);
935         strcpy(pushing_address, remote_address);
936
937         bt_push_responded_cb = responded_cb;
938         bt_progress_cb = progress_cb;
939         bt_finished_cb = finished_cb;
940         opp_client_data = user_data;
941
942         ret = bt_opp_client_push_file(remote_address);
943
944         if (ret == 1) {
945                 DBG("BT_ERROR_NOW_IN_PROGRESS");
946                 return BT_ERROR_NOW_IN_PROGRESS;
947         }
948
949         return ret;
950 }
951
952 int bt_opp_client_cancel_push(void)
953 {
954         int user_privilieges;
955
956         if (strlen(pushing_address) == 0) {
957                 DBG("not need to cancel bonding");
958                 return BT_ERROR_NOT_ENABLED;
959         }
960
961         user_privilieges = bt_device_get_privileges(pushing_address);
962         memset(pushing_address, 0, ADDRESS_LEN);
963
964         if (user_privilieges == 0) {
965                 DBG("user not privilieges to pair and use");
966                 /*todo: This point will check if Cynara allow user
967                         use the remote device
968                         if ok, return BT_SUCCESS.
969                 */
970                 return BT_ERROR_NOT_ENABLED;
971         }
972
973         comms_bluetooth_opp_cancel_transfers(NULL, NULL);
974
975         return 0;
976 }
977