Add the info dbus message of transfer cancel
[platform/core/connectivity/bluetooth-frwk.git] / src / opp.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/file.h>
21 #include <sys/stat.h>
22 #include <sys/mman.h>
23 #include <sys/param.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <gio/gunixfdlist.h>
27 #include <string.h>
28 #include "obex.h"
29 #include "comms_error.h"
30 #include "gdbus.h"
31 #include "opp.h"
32 #include "vertical.h"
33
34 #define OPP_OBJECT "/org/tizen/comms/bluetooth"
35 #define AGENT_INTERFACE "org.bluez.obex.Agent1"
36 #define OPP_AGENT_PATH OPP_OBJECT "/agent/opp"
37
38 #define FILENAME_LEN 100
39 #define ADDRESS_LEN 18
40 #define UID_LEN 8
41 #define CONTEXT_LEN 28
42
43 struct user_privileges {
44         char address[ADDRESS_LEN];
45         char uid[UID_LEN];
46 };
47
48 G_DEFINE_TYPE(OppSkeleton, opp_skeleton,
49                                 G_TYPE_DBUS_INTERFACE_SKELETON);
50
51 static void opp_skeleton_init(OppSkeleton *skeleton)
52 {
53         DBG("");
54
55         obex_lib_init();
56 }
57
58 static void opp_skeleton_finalize(GObject *object)
59 {
60         DBG("");
61
62         obex_lib_deinit();
63 }
64
65 static const GDBusMethodInfo * const _method_info_pointers[] =
66 {
67         GDBUS_METHOD("RegisterObexAgent", GDBUS_ARGS(_ARG("agent", "o")), NULL),
68         GDBUS_METHOD("UnregisterObexAgent", GDBUS_ARGS(_ARG("agent", "o")), NULL),
69         GDBUS_METHOD("AddFile", GDBUS_ARGS(_ARG("sourcefile", "s"),
70                                                 _ARG("agent", "o")), NULL),
71         GDBUS_METHOD("SendFile", GDBUS_ARGS(_ARG("address", "s"),
72                                                 _ARG("agent", "o")), NULL),
73         GDBUS_METHOD("CancelTransfer", GDBUS_ARGS(_ARG("transfer_id", "i")), NULL),
74         GDBUS_METHOD("CancelAllTransfer", NULL, NULL),
75         GDBUS_METHOD("AddNotify", GDBUS_ARGS(_ARG("path", "s")), NULL),
76         GDBUS_METHOD("RemoveFiles", GDBUS_ARGS(_ARG("agent", "o")), NULL),
77         NULL
78 };
79
80 static const GDBusPropertyInfo * const _opp_property_info_pointers[] = {
81         GDBUS_PROPERTY("address", "s",
82                 G_DBUS_PROPERTY_INFO_FLAGS_READABLE),
83         GDBUS_PROPERTY("name", "s",
84                         G_DBUS_PROPERTY_INFO_FLAGS_READABLE),
85         GDBUS_PROPERTY("size", "t",
86                         G_DBUS_PROPERTY_INFO_FLAGS_READABLE),
87         GDBUS_PROPERTY("transfer_id", "i",
88                         G_DBUS_PROPERTY_INFO_FLAGS_READABLE),
89         GDBUS_PROPERTY("state", "i",
90                         G_DBUS_PROPERTY_INFO_FLAGS_READABLE),
91         GDBUS_PROPERTY("percent", "d",
92                         G_DBUS_PROPERTY_INFO_FLAGS_READABLE),
93         GDBUS_PROPERTY("pid", "u",
94                         G_DBUS_PROPERTY_INFO_FLAGS_READABLE),
95         NULL
96 };
97
98 static const GDBusInterfaceInfo _opp_interface_info =
99 {
100         -1,
101         (gchar *) "org.tizen.comms.opp",
102         (GDBusMethodInfo **) &_method_info_pointers,
103         NULL,
104         (GDBusPropertyInfo **) &_opp_property_info_pointers,
105         NULL
106 };
107
108 static GDBusInterfaceInfo *opp_skeleton_get_info(
109                                         GDBusInterfaceSkeleton *skeleton)
110 {
111         return (GDBusInterfaceInfo *) &_opp_interface_info;
112 }
113
114 struct agent {
115         gchar *owner;
116         gchar *object_path;
117         gchar *session;
118         gchar *transfer_path;
119         gchar *address;
120         guint32 pid;
121         guint32 uid;
122         gint number;
123         guint watch_id;
124 };
125
126 struct pending_files {
127         gchar *owner;
128         gchar *object_path;
129         gchar *path;
130         gchar *file_name;
131 };
132
133 struct opp_context {
134         gchar *method_name;
135         GVariant *parameters;
136         GDBusMethodInvocation *invocation;
137         gpointer user_data;
138 };
139
140 struct opp_push_data {
141         gchar *address;
142         GDBusMethodInvocation *invocation;
143         gboolean invocation_useable;
144 };
145
146 struct agent_reply_data {
147         GDBusConnection *connection;
148         GDBusMethodInvocation *invocation;
149 };
150
151 static GDBusObjectSkeleton *bt_object_skeleton;
152 static OppSkeleton *bt_opp;
153 static GDBusNodeInfo *opp_introspection_data;
154 static struct opp_context *opp_context;
155 static guint relay_agent_timeout_id;
156 static guint opp_agent_dbus_id;
157 static struct agent *relay_agent;
158 static struct agent *relay_client_agent;
159 static GDBusConnection *session_connection;
160
161 static GList *agent_list;
162 static GList *agent_server_list;
163 static GList *pending_push_data;
164 static GList *pending_p_list;
165
166 #define OBEX_ERROR_INTERFACE "org.bluez.obex.Error"
167
168 static void free_remove_relay_agent(void);
169 static void free_pending_files(struct pending_files *p_file);
170 static void free_relay_agent(struct agent *agent);
171 static void session_state_cb(const gchar *session_id,
172                                 const gchar *session,
173                                 enum session_state state,
174                                 void *user_data,
175                                 char *error_msg);
176 static struct agent *find_agent(GList *agent_l,
177                         const char *sender, const char *path);
178
179 static void bt_opp_register_dbus_interface(OppSkeleton *skeleton,
180                                         GDBusConnection *connection)
181 {
182         GDBusInterfaceSkeleton *opp_interface;
183
184         opp_interface = G_DBUS_INTERFACE_SKELETON(skeleton);
185
186         g_dbus_object_skeleton_add_interface(bt_object_skeleton,
187                                                         opp_interface);
188 }
189
190 static void bt_opp_unregister_dbus_interface()
191 {
192         GDBusInterfaceSkeleton *opp_interface;
193
194         opp_interface = G_DBUS_INTERFACE_SKELETON(bt_opp);
195         g_dbus_object_skeleton_remove_interface(bt_object_skeleton,
196                                                         opp_interface);
197 }
198
199 static void destruct_opp_agent(GDBusConnection *connection)
200 {
201         if (opp_agent_dbus_id > 0)
202                 g_dbus_connection_unregister_object(connection,
203                                                 opp_agent_dbus_id);
204
205         g_dbus_node_info_unref(opp_introspection_data);
206 }
207
208 static guint32 get_connection_p_id(GDBusConnection *connection,
209                                                 const gchar *sender)
210 {
211         GError *error = NULL;
212         GVariant *pidvalue;
213         guint32 pid;
214
215         DBG("");
216
217         pidvalue = g_dbus_connection_call_sync(connection,
218                                 "org.freedesktop.DBus",
219                                 "/org/freedesktop/DBus",
220                                 "org.freedesktop.DBus",
221                                 "GetConnectionUnixProcessID",
222                                 g_variant_new("(s)", sender),
223                                 NULL, 0, -1, NULL, &error);
224
225         if (pidvalue == NULL) {
226                 DBG("GetConnectionUnixUser: %s", error->message);
227                 g_error_free(error);
228                 return -1;
229         }
230
231         g_variant_get(pidvalue, "(u)", &pid);
232         g_variant_unref(pidvalue);
233
234         return pid;
235 }
236
237 static guint32 get_connection_user_id(GDBusConnection *connection,
238                                                 const gchar *sender)
239 {
240         GError *error = NULL;
241         GVariant *uidvalue;
242         guint32 uid;
243
244         DBG("");
245
246         uidvalue = g_dbus_connection_call_sync(connection,
247                                 "org.freedesktop.DBus",
248                                 "/org/freedesktop/DBus",
249                                 "org.freedesktop.DBus",
250                                 "GetConnectionUnixUser",
251                                 g_variant_new("(s)", sender),
252                                 NULL, 0, -1, NULL, &error);
253
254         if (uidvalue == NULL) {
255                 DBG("GetConnectionUnixUser: %s", error->message);
256                 g_error_free(error);
257                 return -1;
258         }
259
260         g_variant_get(uidvalue, "(u)", &uid);
261         g_variant_unref(uidvalue);
262
263         return uid;
264 }
265
266 static void handle_pushstatus(GVariant *parameters)
267 {
268         GDBusConnection *connection;
269         DBG("");
270
271         connection = g_dbus_interface_skeleton_get_connection(
272                                 G_DBUS_INTERFACE_SKELETON(bt_opp));
273
274         g_dbus_connection_emit_signal(connection, NULL,
275                                 "/org/tizen/comms/bluetooth",
276                                 "org.freedesktop.DBus.Properties",
277                                 "PropertiesChanged",
278                                 parameters,
279                                 NULL);
280
281         return;
282 }
283
284 void send_pushstatus(char *destination, const char *name, guint64 size,
285                         guint transfer_id, enum transfer_state state,
286                                         double percent, guint32 pid)
287 {
288         GVariant *parameters;
289         GVariantBuilder *builder;
290         GVariant *val;
291
292         DBG("");
293
294         builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
295         if (destination)
296                 val = g_variant_new("s", destination);
297         else
298                 val = g_variant_new("s", "");
299         g_variant_builder_add(builder, "{sv}", "address", val);
300         if (name)
301                 val = g_variant_new("s", name);
302         else
303                 val = g_variant_new("s", "");
304         g_variant_builder_add(builder, "{sv}", "name", val);
305         val = g_variant_new("t", size);
306         g_variant_builder_add(builder, "{sv}", "size", val);
307         val = g_variant_new("i", transfer_id);
308         g_variant_builder_add(builder, "{sv}", "transfer_id", val);
309         val = g_variant_new("i", state);
310         g_variant_builder_add(builder, "{sv}", "state", val);
311         val = g_variant_new("d", percent);
312         g_variant_builder_add(builder, "{sv}", "percent", val);
313         val = g_variant_new("u", pid);
314         g_variant_builder_add(builder, "{sv}", "pid", val);
315
316         parameters = g_variant_ref_sink(g_variant_new("(sa{sv}as)",
317                                         "org.tizen.comms.opp",
318                                         builder, NULL));
319
320         handle_pushstatus(parameters);
321 }
322
323 static void transfer_watched_cb(
324                         const char *transfer_path,
325                         enum transfer_state state,
326                         const char *name,
327                         guint64 size,
328                         guint64 transferred,
329                         void *data,
330                         char *error_msg)
331 {
332         struct pending_files *p_file = data;
333         guint transfer_id;
334
335         DBG("");
336
337         transfer_id = obex_get_transfer_id(transfer_path, OBEX_CLIENT);
338
339         DBG("state: %d, %d, %s, %ju", state, transfer_id,
340                                                 name, size);
341         if (state == OBEX_TRANSFER_ERROR) {
342                 vertical_notify_bt_transfer(0);
343                 if (relay_client_agent)
344                         send_pushstatus(relay_client_agent->address,
345                                 name, size, transfer_id, state, 0,
346                                 relay_client_agent->pid);
347                 relay_client_agent->number = 0;
348                 goto done;
349         }
350
351         if (state == OBEX_TRANSFER_QUEUED) {
352                 vertical_notify_bt_transfer(0);
353                 if (relay_client_agent)
354                         send_pushstatus(relay_client_agent->address,
355                                 name, size, transfer_id, state, 0,
356                                 relay_client_agent->pid);
357                 return;
358         }
359
360         if (state == OBEX_TRANSFER_COMPLETE) {
361                 vertical_notify_bt_transfer(100);
362                 relay_client_agent->number--;
363                 goto done;
364         }
365
366         if (state == OBEX_TRANSFER_ACTIVE) {
367                 double percent = 0;
368
369                 DBG("transferred %ju, size %ju", transferred, size);
370                 percent = (double) transferred * 100 / size;
371
372                 vertical_notify_bt_transfer(percent);
373                 if (relay_client_agent)
374                         send_pushstatus(relay_client_agent->address,
375                                 name, size, transfer_id, state, percent,
376                                 relay_client_agent->pid);
377                 return;
378         }
379 done:
380         if (relay_client_agent) {
381                 if (state == OBEX_TRANSFER_COMPLETE)
382                         send_pushstatus(relay_client_agent->address,
383                                         name, size, transfer_id, state,
384                                         100, relay_client_agent->pid);
385                 if (!relay_client_agent->number)
386                         free_remove_relay_agent();
387         }
388
389         if (p_file) {
390                 pending_p_list = g_list_remove(pending_p_list, p_file);
391                 free_pending_files(p_file);
392         }
393 }
394
395 static void transfer_server_watched_cb(
396                         const char *transfer_path,
397                         enum transfer_state state,
398                         const char *name,
399                         guint64 size,
400                         guint64 transferred,
401                         void *data,
402                         char *error_msg)
403 {
404         guint transfer_id;
405
406         DBG("");
407
408         transfer_id = obex_get_transfer_id(transfer_path, OBEX_SERVER);
409
410         if (relay_agent && !relay_agent->transfer_path)
411                 relay_agent->transfer_path = g_strdup(transfer_path);
412
413         DBG("state: %d, %d, %s, %ju", state, transfer_id,
414                                                 name, size);
415
416         if (state == OBEX_TRANSFER_ERROR) {
417                 vertical_notify_bt_transfer(0);
418                 if (relay_agent) {
419                         send_pushstatus(relay_agent->address,
420                                 name, size, transfer_id, state, 0,
421                                 relay_agent->pid);
422                         g_free(relay_agent->transfer_path);
423                         relay_agent->transfer_path = NULL;
424                 }
425                 return;
426         }
427
428         if (state == OBEX_TRANSFER_QUEUED) {
429                 vertical_notify_bt_transfer(0);
430                 if (relay_agent)
431                         send_pushstatus(relay_agent->address,
432                                 name, size, transfer_id, state, 0,
433                                 relay_agent->pid);
434                 return;
435         }
436
437         if (state == OBEX_TRANSFER_COMPLETE) {
438                 vertical_notify_bt_transfer(100);
439                 if (relay_agent) {
440                         send_pushstatus(relay_agent->address,
441                                 name, size, transfer_id, state, 100,
442                                 relay_agent->pid);
443                         g_free(relay_agent->transfer_path);
444                         relay_agent->transfer_path = NULL;
445                 }
446                 return;
447         }
448
449         if (state == OBEX_TRANSFER_ACTIVE) {
450                 double percent = 0;
451
452                 DBG("transferred %ju, size %ju", transferred, size);
453                 percent = (double) transferred * 100 / size;
454
455                 vertical_notify_bt_transfer(percent);
456                 if (relay_agent)
457                         send_pushstatus(relay_agent->address,
458                                 name, size, transfer_id, state, percent,
459                                 relay_agent->pid);
460                 return;
461         }
462 }
463
464 static void register_obex_agent_cb(enum bluez_error_type type, void *user_data)
465 {
466         GDBusConnection *connection = user_data;
467
468         if (type != ERROR_NONE) {
469                 destruct_opp_agent(session_connection);
470
471                 g_object_unref(session_connection);
472
473                 g_object_unref(bt_opp);
474                 bt_opp = NULL;
475
476                 return;
477         }
478
479         bt_opp_register_dbus_interface(bt_opp, connection);
480 }
481
482 static void unregister_obex_agent_cb(enum bluez_error_type type, void *user_data)
483 {
484         if (type != ERROR_NONE)
485                 ERROR("unregister obex agent failed :%d", type);
486
487         destruct_opp_agent(session_connection);
488
489         bt_opp_unregister_dbus_interface();
490
491         g_object_unref(session_connection);
492         g_object_unref(bt_opp);
493         bt_opp = NULL;
494 }
495
496 static void agent_request_release_reply(GObject *source_object,
497                                         GAsyncResult *result,
498                                         gpointer user_data)
499 {
500         GVariant *ret;
501         GError *error = NULL;
502         struct agent_reply_data *reply_data = user_data;
503
504         ret = g_dbus_connection_call_finish(reply_data->connection,
505                                                         result, &error);
506
507         g_dbus_method_invocation_return_value(reply_data->invocation, ret);
508
509         g_free(reply_data);
510 }
511
512 static void authorize_push_reply(GObject *source_object,
513                                         GAsyncResult *result,
514                                         gpointer user_data)
515 {
516         GVariant *ret;
517         GError *error = NULL;
518         struct agent_reply_data *reply_data = user_data;
519
520         ret = g_dbus_connection_call_finish(reply_data->connection,
521                                                         result, &error);
522
523         if (ret == NULL) {
524                 WARN("%s", error->message);
525
526                 if (g_strrstr(error->message, "org.bluez.Error.Rejected"))
527                         g_dbus_method_invocation_return_dbus_error(
528                                                 reply_data->invocation,
529                                                 OBEX_ERROR_INTERFACE ".Rejected",
530                                                 "RejectByUser");
531                 else if (g_strrstr(error->message, "org.bluez.Error.Canceled"))
532                         g_dbus_method_invocation_return_dbus_error(
533                                                 reply_data->invocation,
534                                                 OBEX_ERROR_INTERFACE ".Cancel",
535                                                 "CancelByUser");
536                 else
537                         comms_error_failed(reply_data->invocation, "Failed");
538
539                 g_free(reply_data);
540                 return;
541         }
542
543         g_dbus_method_invocation_return_value(reply_data->invocation, ret);
544
545         g_free(reply_data);
546 }
547
548 static void agent_request_cancel_reply(GObject *source_object,
549                                         GAsyncResult *result,
550                                         gpointer user_data)
551 {
552         GVariant *ret;
553         GError *error = NULL;
554         struct agent_reply_data *reply_data = user_data;
555
556         ret = g_dbus_connection_call_finish(reply_data->connection,
557                                                         result, &error);
558
559         g_dbus_method_invocation_return_value(reply_data->invocation, ret);
560
561         g_free(reply_data);
562 }
563
564 static const gchar opp_introspection_xml[] =
565         "<node>"
566         "  <interface name='org.bluez.obex.Agent1'>"
567         "    <method name='Release'>"
568         "    </method>"
569         "    <method name='AuthorizePush'>"
570         "      <arg type='o' name='transfer' direction='in'/>"
571         "      <arg type='s' direction='out'/>"
572         "    </method>"
573         "    <method name='Cancel'>"
574         "    </method>"
575         "  </interface>"
576         "</node>";
577
578 static void handle_release(GDBusConnection *connection,
579                                 GVariant *parameters,
580                                 GDBusMethodInvocation *invocation,
581                                 gpointer user_data)
582 {
583         struct agent_reply_data *reply_data;
584
585         DBG("");
586
587         reply_data = g_new0(struct agent_reply_data, 1);
588
589         reply_data->connection = connection;
590         reply_data->invocation = invocation;
591
592         g_dbus_connection_call(connection,
593                                 relay_agent->owner,
594                                 relay_agent->object_path,
595                                 AGENT_INTERFACE,
596                                 "Release",
597                                 NULL,
598                                 NULL,
599                                 G_DBUS_CALL_FLAGS_NONE,
600                                 -1, NULL,
601                                 agent_request_release_reply,
602                                 reply_data);
603 }
604
605 static int get_privileges_uid(gchar *address)
606 {
607         char file[FILENAME_LEN];
608         char context[CONTEXT_LEN];
609         char *path = getenv("HOME");
610         int fd;
611         struct user_privileges *privileges = NULL;
612         int len;
613         struct stat st;
614         int privileges_uid;
615         int ret;
616
617         DBG("");
618
619         sprintf(file, "%s/.bt_userprivileges", path);
620
621         fd = open(file, O_RDONLY, S_IRUSR | S_IWUSR);
622
623         if (fd < 0) {
624                 DBG("fd = %d", fd);
625                 return -1;
626         }
627
628         if (fstat(fd, &st) < 0) {
629                 close(fd);
630                 DBG("privileges context error");
631                 return -1;
632         }
633
634         len = st.st_size;
635         lseek(fd, 0, SEEK_SET);
636
637         while (len >= CONTEXT_LEN) {
638                 memset(context, 0, CONTEXT_LEN);
639                 ret = read(fd, context, CONTEXT_LEN-2);
640                 if (ret <= 0) {
641                         DBG("read error");
642                         close(fd);
643                         return -1;
644                 }
645                 privileges = (struct user_privileges *)context;
646                 privileges->address[ADDRESS_LEN-1] = 0;
647                 privileges_uid = atoi(privileges->uid);
648                 if (!strcasecmp(address, privileges->address)) {
649                         DBG("find privileges matched user");
650                         close(fd);
651                         return privileges_uid;
652                 }
653                 len -= CONTEXT_LEN;
654                 lseek(fd, 2, SEEK_CUR);
655         }
656
657         close(fd);
658
659         return -1;
660 }
661
662 static struct agent *find_server_agent(guint32 uid)
663 {
664         struct agent *agent;
665         GList *list, *next;
666
667         DBG("uid = %d", uid);
668
669         if (agent_server_list == NULL)
670                 return NULL;
671
672         for (list = g_list_first(agent_server_list);
673                                 list; list = next) {
674                 next = g_list_next(list);
675                 agent = list->data;
676
677                 if (agent && (agent->uid == uid))
678                         return agent;
679         }
680
681         return NULL;
682 }
683
684 static void handle_authorize_push(GDBusConnection *connection,
685                                 GVariant *parameters,
686                                 GDBusMethodInvocation *invocation,
687                                 gpointer user_data)
688 {
689         struct agent_reply_data *reply_data;
690         gchar *transfer_path = NULL;
691         gchar *destination = NULL;
692         gchar *name = NULL;
693         guint64 size = 0;
694         guint transfer_id = 0;
695         int uid;
696         GVariant *param;
697         struct agent *agent = NULL;
698
699         DBG("");
700
701         reply_data = g_new0(struct agent_reply_data, 1);
702
703         reply_data->connection = connection;
704         reply_data->invocation = invocation;
705
706         g_variant_get(parameters, "(o)", &transfer_path);
707
708         obex_transfer_get_property_size(transfer_path, &size);
709         name = obex_transfer_get_property_name(transfer_path);
710         if (!name)
711                 name = "";
712         destination = obex_transfer_get_property_destination(transfer_path);
713         if (!destination)
714                 destination = "";
715         transfer_id = obex_get_transfer_id(transfer_path, OBEX_SERVER);
716
717         uid = get_privileges_uid(destination);
718         DBG("destination = %s, uid = %d", destination, uid);
719
720         if (uid > -1)
721                 agent = find_server_agent(uid);
722
723         if (agent)
724                 relay_agent = agent;
725
726         param = g_variant_new("(sssti)",
727                         destination, name, transfer_path, size, transfer_id);
728
729         g_dbus_connection_call(connection,
730                                 relay_agent->owner,
731                                 relay_agent->object_path,
732                                 AGENT_INTERFACE,
733                                 "AuthorizePush",
734                                 param,
735                                 g_variant_type_new("(s)"),
736                                 G_DBUS_CALL_FLAGS_NONE,
737                                 -1, NULL,
738                                 authorize_push_reply,
739                                 reply_data);
740 }
741
742 static void handle_cancel(GDBusConnection *connection,
743                                 GVariant *parameters,
744                                 GDBusMethodInvocation *invocation,
745                                 gpointer user_data)
746 {
747         struct agent_reply_data *reply_data;
748
749         DBG("");
750
751         reply_data = g_new0(struct agent_reply_data, 1);
752
753         reply_data->connection = connection;
754         reply_data->invocation = invocation;
755
756         g_dbus_connection_call(connection,
757                                 relay_agent->owner,
758                                 relay_agent->object_path,
759                                 AGENT_INTERFACE,
760                                 "Cancel",
761                                 NULL,
762                                 NULL,
763                                 G_DBUS_CALL_FLAGS_NONE,
764                                 -1, NULL,
765                                 agent_request_cancel_reply,
766                                 reply_data);
767 }
768
769 static void handle_opp_context(GDBusConnection *connection,
770                                 struct opp_context *context)
771 {
772         gchar *method_name = context->method_name;
773         if (g_strcmp0(method_name, "Release") == 0)
774                 handle_release(connection,
775                                 context->parameters,
776                                 context->invocation,
777                                 context->user_data);
778         else if (g_strcmp0(method_name, "AuthorizePush") == 0)
779                 handle_authorize_push(connection,
780                                 context->parameters,
781                                 context->invocation,
782                                 context->user_data);
783         else if (g_strcmp0(method_name, "Cancel") == 0)
784                 handle_cancel(connection,
785                                 context->parameters,
786                                 context->invocation,
787                                 context->user_data);
788         else
789                 WARN("Unknown method %s", method_name);
790 }
791
792 static struct opp_context *create_opp_context(const gchar *method_name,
793                                         GVariant *parameters,
794                                         GDBusMethodInvocation *invocation,
795                                         gpointer user_data)
796 {
797         struct opp_context *context;
798
799         context = g_new0(struct opp_context, 1);
800         if (context == NULL) {
801                 ERROR("no memroy");
802
803                 return NULL;
804         }
805
806         context->method_name = g_strdup(method_name);
807         context->parameters = g_variant_ref_sink(parameters);
808         context->invocation = invocation;
809         context->user_data = user_data;
810
811         return context;
812 }
813
814 static void free_opp_context(gpointer user_data)
815 {
816         struct opp_context *context = user_data;
817
818         g_free(context->method_name);
819         g_variant_unref(context->parameters);
820
821         g_free(context);
822 }
823
824 static gboolean relay_agent_timeout_cb(gpointer user_data)
825 {
826         DBG("");
827
828         comms_error_failed(opp_context->invocation, "Relay agent timeout");
829
830         free_opp_context(opp_context);
831
832         opp_context = NULL;
833
834         return FALSE;
835 }
836
837 static void handle_opp_agent_method_call(GDBusConnection *connection,
838                                         const gchar *sender,
839                                         const gchar *object_path,
840                                         const gchar *interface,
841                                         const gchar *method_name,
842                                         GVariant *parameters,
843                                         GDBusMethodInvocation *invocation,
844                                         gpointer user_data)
845 {
846         opp_context = create_opp_context(method_name, parameters,
847                                         invocation, user_data);
848
849         if (relay_agent) {
850                 GDBusConnection *system_connection;
851
852                 system_connection = g_dbus_interface_skeleton_get_connection(
853                                         G_DBUS_INTERFACE_SKELETON(bt_opp));
854
855                 handle_opp_context(system_connection, opp_context);
856
857                 free_opp_context(opp_context);
858
859                 opp_context = NULL;
860
861                 return;
862         }
863
864         vertical_notify_bt_opp_agent_on(NULL);
865
866         relay_agent_timeout_id = g_timeout_add(500,
867                                         relay_agent_timeout_cb, NULL);
868 }
869
870 static const GDBusInterfaceVTable opp_agent_vtable =
871 {
872         handle_opp_agent_method_call,
873         NULL,
874         NULL
875 };
876
877 static gboolean create_opp_agent(GDBusConnection *connection)
878 {
879         opp_introspection_data = g_dbus_node_info_new_for_xml(
880                                                 opp_introspection_xml, NULL);
881         if (opp_introspection_data == NULL)
882                 return FALSE;
883
884         opp_agent_dbus_id = g_dbus_connection_register_object(connection,
885                                                 OPP_AGENT_PATH,
886                                                 opp_introspection_data->interfaces[0],
887                                                 &opp_agent_vtable,
888                                                 NULL, NULL, NULL);
889         if (opp_agent_dbus_id < 0) {
890                 ERROR("Register OPP Agent Failed");
891                 return FALSE;
892         }
893
894         return TRUE;
895 }
896
897 static struct pending_files *create_pending_files(const gchar *sender,
898                                 const gchar *path, const gchar *file_name)
899 {
900         struct pending_files *p_file;
901
902         DBG("");
903
904         p_file = g_new0(struct pending_files, 1);
905         if (p_file == NULL) {
906                 ERROR("no memory");
907                 return NULL;
908         }
909
910         p_file->owner = g_strdup(sender);
911         p_file->object_path = g_strdup(path);
912         p_file->file_name = g_strdup(file_name);
913
914         return p_file;
915 }
916
917 static void free_pending_files(struct pending_files *p_file)
918 {
919         DBG("+");
920
921         if (!p_file)
922                 return;
923
924         if (p_file->owner)
925                 g_free(p_file->owner);
926         if (p_file->object_path)
927                 g_free(p_file->object_path);
928         if (p_file->file_name)
929                 g_free(p_file->file_name);
930         if (p_file->path)
931                 g_free(p_file->path);
932         g_free(p_file);
933         p_file = NULL;
934
935         DBG("-");
936 }
937
938 static void free_all_pending_files(void)
939 {
940         GList *list, *next;
941         struct pending_files *p_file;
942
943         DBG("+");
944
945         if (!pending_p_list ||
946                 g_list_length(pending_p_list) == 0)
947                 return;
948
949         for (list = g_list_first(pending_p_list); list; list = next) {
950                 next = g_list_next(list);
951                 p_file = list->data;
952                 pending_p_list = g_list_remove(pending_p_list, p_file);
953                 if (p_file)
954                         free_pending_files(p_file);
955         }
956
957         pending_p_list = NULL;
958
959         DBG("-");
960 }
961
962 static void free_remove_relay_agent(void)
963 {
964         GList *list;
965
966         DBG("");
967
968         if (relay_client_agent) {
969                 obex_session_remove_session(
970                         relay_client_agent->session);
971                 free_relay_agent(relay_client_agent);
972         }
973         relay_client_agent = NULL;
974
975         if (g_list_length(agent_list) > 0) {
976                 list = g_list_first(agent_list);
977                 relay_client_agent = list->data;
978                 agent_list = g_list_remove(
979                         agent_list, relay_client_agent);
980                 obex_create_session(relay_client_agent->address,
981                         OBEX_OPP, session_state_cb, NULL);
982         }
983 }
984
985 static struct agent *create_relay_agent(const gchar *sender,
986                                 const gchar *path, const gchar *address,
987                                 guint32 pid, guint32 uid, guint watch_id)
988 {
989         struct agent *agent;
990
991         agent = g_new0(struct agent, 1);
992         if (agent == NULL) {
993                 ERROR("no memory");
994                 return NULL;
995         }
996
997         agent->owner = g_strdup(sender);
998         agent->object_path = g_strdup(path);
999         agent->address = g_strdup(address);
1000         agent->watch_id = watch_id;
1001         agent->pid = pid;
1002         agent->uid = uid;
1003
1004         return agent;
1005 }
1006
1007 static void free_relay_agent(struct agent *agent)
1008 {
1009         if (!agent)
1010                 return;
1011
1012         if (agent->owner)
1013                 g_free(agent->owner);
1014         if (agent->object_path)
1015                 g_free(agent->object_path);
1016         if (agent->session)
1017                 g_free(agent->session);
1018         if (agent->transfer_path)
1019                 g_free(agent->transfer_path);
1020
1021         g_free(agent);
1022 }
1023
1024 static void relay_agent_disconnected(GDBusConnection *connection,
1025                                         const gchar *name, gpointer user_data)
1026 {
1027         struct agent *agent = (struct agent *)user_data;
1028
1029         DBG("");
1030
1031         if (agent == NULL)
1032                 return;
1033
1034         agent_server_list = g_list_remove(agent_server_list, agent);
1035
1036         if (relay_agent)
1037                 if (!g_strcmp0(agent->object_path, relay_agent->object_path) &&
1038                                 !g_strcmp0(agent->owner, relay_agent->owner)) {
1039                         GList *next;
1040                         next = g_list_last(agent_server_list);
1041                         if (next)
1042                                 relay_agent = next->data;
1043                         else
1044                                 relay_agent = NULL;
1045         }
1046
1047         free_relay_agent(agent);
1048 }
1049
1050 static void relay_client_agent_disconnected(GDBusConnection *connection,
1051                                         const gchar *name, gpointer user_data)
1052 {
1053         DBG("");
1054
1055         if (!relay_client_agent)
1056                 return;
1057
1058         free_relay_agent(relay_client_agent);
1059
1060         relay_client_agent = NULL;
1061 }
1062
1063 static void register_relay_agent_handler(GDBusConnection *connection,
1064                                         GVariant *parameters,
1065                                         GDBusMethodInvocation *invocation,
1066                                         gpointer user_data)
1067 {
1068         const gchar *sender;
1069         gchar *agent_path;
1070         guint relay_agent_watch_id;
1071         guint32 uid, pid;
1072         struct agent *agent = NULL;
1073
1074         DBG("");
1075
1076         g_variant_get(parameters, "(o)", &agent_path);
1077         if (agent_path == NULL)
1078                 return comms_error_invalid_args(invocation);
1079
1080         sender = g_dbus_method_invocation_get_sender(invocation);
1081         uid = get_connection_user_id(connection, sender);
1082
1083         agent = find_server_agent(uid);
1084         if (agent != NULL)
1085                 return comms_error_already_done(invocation);
1086
1087         pid = get_connection_p_id(connection, sender);
1088
1089         relay_agent_watch_id =
1090                         g_bus_watch_name_on_connection(connection, sender,
1091                                         G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
1092                                         NULL, relay_agent_disconnected,
1093                                         NULL, NULL);
1094
1095         relay_agent = create_relay_agent(sender, agent_path, NULL, pid,
1096                                         uid, relay_agent_watch_id);
1097
1098         agent_server_list = g_list_append(agent_server_list, relay_agent);
1099
1100         if (relay_agent_timeout_id > 0) {
1101                 g_source_remove(relay_agent_timeout_id);
1102
1103                 relay_agent_timeout_id = 0;
1104         }
1105
1106         g_dbus_method_invocation_return_value(invocation, NULL);
1107
1108         if (!opp_context)
1109                 return;
1110
1111         handle_opp_context(connection, opp_context);
1112
1113         free_opp_context(opp_context);
1114
1115         opp_context = NULL;
1116 }
1117
1118 static void unregister_relay_agent_handler(GDBusConnection *connection,
1119                                         GVariant *parameters,
1120                                         GDBusMethodInvocation *invocation,
1121                                         gpointer user_data)
1122 {
1123         gchar *agent_path;
1124         const gchar *sender;
1125         struct agent *agent;
1126
1127         DBG("");
1128
1129         if (relay_agent == NULL)
1130                 return comms_error_does_not_exist(invocation);
1131
1132         sender = g_dbus_method_invocation_get_sender(invocation);
1133
1134         g_variant_get(parameters, "(o)", &agent_path);
1135         if (agent_path == NULL)
1136                 return comms_error_invalid_args(invocation);
1137
1138         agent = find_agent(agent_server_list, sender, agent_path);
1139         if (agent == NULL) {
1140                 DBG("can not find agent");
1141                 return comms_error_does_not_exist(invocation);
1142         }
1143
1144         agent_server_list = g_list_remove(agent_server_list, agent);
1145
1146         if (relay_agent)
1147                 if (!g_strcmp0(agent_path, relay_agent->object_path) &&
1148                         !g_strcmp0(sender, relay_agent->owner)) {
1149                         GList *next;
1150                         next = g_list_last(agent_server_list);
1151                         if (next)
1152                                 relay_agent = next->data;
1153                         else
1154                                 relay_agent = NULL;
1155         }
1156
1157         g_dbus_method_invocation_return_value(invocation, NULL);
1158
1159         g_free(agent_path);
1160
1161         free_relay_agent(agent);
1162 }
1163
1164 char *get_failed_content(const gchar *error_message)
1165 {
1166         const gchar *title = "org.bluez.obex.Error.Failed: ";
1167         gchar *error_str = g_strrstr(error_message, title);
1168
1169         if (error_str == NULL)
1170                 return NULL;
1171
1172         return error_str + strlen(title);
1173 }
1174
1175 static void handle_error_message(GDBusMethodInvocation *invocation,
1176                                                         char *error_msg)
1177 {
1178         if (g_strrstr(error_msg, "org.bluez.obex.Error.InvalidArguments"))
1179                 return comms_error_invalid_args(invocation);
1180         else if (g_strrstr(error_msg, "org.bluez.obex.Error.Failed")) {
1181                 gchar *info = get_failed_content(error_msg);
1182
1183                 return comms_error_failed(invocation, info);
1184         } else
1185                 WARN("Unknown error %s", error_msg);
1186 }
1187
1188 static void transfer_state_cb(
1189                         const char *transfer_path,
1190                         enum transfer_state state,
1191                         const char *name,
1192                         guint64 size,
1193                         guint64 transferred,
1194                         void *data,
1195                         char *error_msg)
1196 {
1197         struct pending_files *p_file = data;
1198
1199         DBG("transfer path %s", transfer_path);
1200         DBG("state %d", state);
1201
1202         if (error_msg) {
1203                 DBG("error = %s", error_msg);
1204                 free_all_pending_files();
1205                 free_remove_relay_agent();
1206                 return;
1207         }
1208
1209         if (state == OBEX_TRANSFER_QUEUED) {
1210                 if (p_file) {
1211                         p_file->path = g_strdup(transfer_path);
1212                         pending_p_list = g_list_append(pending_p_list, p_file);
1213                 }
1214                 obex_transfer_set_notify((char *)transfer_path,
1215                                                 transfer_watched_cb, p_file);
1216         }
1217 }
1218
1219 static void send_pending_push_data(void)
1220 {
1221         struct pending_files *p_file;
1222         gboolean is_send = FALSE;
1223         GList *list, *next;
1224
1225         DBG("");
1226
1227         if (g_list_length(pending_push_data) == 0)
1228                 return;
1229
1230         for (list = g_list_first(pending_push_data); list; list = next) {
1231                 next = g_list_next(list);
1232                 p_file = list->data;
1233
1234                 if (!g_strcmp0(p_file->owner, relay_client_agent->owner) &&
1235                                         !g_strcmp0(p_file->object_path,
1236                                         relay_client_agent->object_path)) {
1237                         DBG("send p_file->file_name = %s", p_file->file_name);
1238                         relay_client_agent->number++;
1239                         obex_session_opp_send_file(relay_client_agent->session,
1240                                                 p_file->file_name,
1241                                                 transfer_state_cb, p_file);
1242                         pending_push_data =
1243                                 g_list_remove(pending_push_data, p_file);
1244                         is_send = TRUE;
1245                 }
1246         }
1247
1248         if (is_send == FALSE)
1249                 free_remove_relay_agent();
1250 }
1251
1252 static void session_state_cb(const gchar *session_id,
1253                                 const gchar *session,
1254                                 enum session_state state,
1255                                 void *user_data,
1256                                 char *error_msg)
1257 {
1258         gchar *name = "OBEX_TRANSFER_QUEUED";
1259         guint64 size = 0;
1260         guint transfer_id = 0;
1261         struct opp_push_data *push_data = user_data;
1262
1263         DBG("%s", error_msg);
1264
1265         if (error_msg) {
1266                 DBG("error = %s", error_msg);
1267                 if (push_data) {
1268                         handle_error_message(
1269                                 push_data->invocation, error_msg);
1270                         g_free(push_data);
1271                 }
1272                 free_remove_relay_agent();
1273                 return;
1274         }
1275
1276         if (relay_client_agent) {
1277                 send_pushstatus(relay_client_agent->address, name, size,
1278                                         transfer_id, OBEX_TRANSFER_QUEUED, 0,
1279                                         relay_client_agent->pid);
1280
1281                 DBG("session = %s", session);
1282                 relay_client_agent->session = g_strdup(session);
1283
1284                 if (g_list_length(pending_push_data) > 0)
1285                         send_pending_push_data();
1286         }
1287
1288         if (push_data) {
1289                 g_dbus_method_invocation_return_value(
1290                                         push_data->invocation, NULL);
1291                 g_free(push_data);
1292         }
1293 }
1294
1295 static struct agent *find_agent(GList *agent_l,
1296                         const char *sender, const char *path)
1297 {
1298         struct agent *agent;
1299         GList *list, *next;
1300
1301         DBG("sender = %s, path = %s", sender, path);
1302
1303         if (agent_l == NULL)
1304                 return NULL;
1305
1306         for (list = g_list_first(agent_l); list; list = next) {
1307                 next = g_list_next(list);
1308
1309                 agent = list->data;
1310
1311                 if (agent && !g_strcmp0(agent->owner, sender)
1312                                 && !g_strcmp0(agent->object_path, path))
1313                         return agent;
1314         }
1315
1316         return NULL;
1317 }
1318
1319 static gboolean find_pending_files(const char *sender, const char *path)
1320 {
1321         struct pending_files *p_file;
1322         GList *list, *next;
1323
1324         DBG("sender = %s, path = %s", sender, path);
1325
1326         if (pending_push_data == NULL)
1327                 return FALSE;
1328
1329         for (list = g_list_first(pending_push_data); list; list = next) {
1330                 next = g_list_next(list);
1331
1332                 p_file = list->data;
1333
1334                 if (p_file && !g_strcmp0(p_file->owner, sender)
1335                                 && !g_strcmp0(p_file->object_path, path))
1336                         return TRUE;
1337         }
1338
1339         return FALSE;
1340 }
1341
1342 static struct agent *create_relay_client_agent(GDBusConnection *connection,
1343                                 const gchar *sender, const gchar *address,
1344                                 const gchar *agent, guint32 pid)
1345 {
1346         guint relay_agent_watch_id;
1347         struct agent *client_agent;
1348
1349         relay_agent_watch_id =
1350                         g_bus_watch_name_on_connection(connection, sender,
1351                                         G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
1352                                         NULL, relay_client_agent_disconnected,
1353                                         NULL, NULL);
1354
1355         client_agent = create_relay_agent(sender, agent, address, pid, 0,
1356                                                         relay_agent_watch_id);
1357
1358         return client_agent;
1359 }
1360
1361
1362 static void remove_file_handler(GDBusConnection *connection,
1363                                 GVariant *parameters,
1364                                 GDBusMethodInvocation *invocation,
1365                                 gpointer user_data)
1366 {
1367         struct agent *agent;
1368         const gchar *sender, *path;
1369         struct pending_files *p_file;
1370         GList *list, *next;
1371
1372         sender = g_dbus_method_invocation_get_sender(invocation);
1373
1374         DBG("sender = %s", sender);
1375
1376         if (agent_list == NULL)
1377                 return comms_error_failed(invocation, "Failed");
1378
1379         g_variant_get(parameters, "(o)", &path);
1380
1381         for (list = g_list_first(agent_list); list; list = next) {
1382                 next = g_list_next(list);
1383                 agent = list->data;
1384
1385                 if (agent && !g_strcmp0(agent->owner, sender)
1386                         && !g_strcmp0(agent->object_path, path)) {
1387                         agent_list = g_list_remove(agent_list, agent);
1388                         free_relay_agent(agent);
1389                         break;
1390                 }
1391         }
1392
1393         for (list = g_list_first(pending_push_data); list; list = next) {
1394                 next = g_list_next(list);
1395
1396                 p_file = list->data;
1397                 if (p_file && !g_strcmp0(p_file->owner, sender)
1398                                 && !g_strcmp0(p_file->object_path, path)) {
1399                         pending_push_data =
1400                                 g_list_remove(pending_push_data, p_file);
1401                         free_pending_files(p_file);
1402                 }
1403         }
1404
1405         return g_dbus_method_invocation_return_value(invocation, NULL);
1406 }
1407
1408 static void add_file_handler(GDBusConnection *connection,
1409                                 GVariant *parameters,
1410                                 GDBusMethodInvocation *invocation,
1411                                 gpointer user_data)
1412 {
1413         const gchar *file_name;
1414         const gchar *agent;
1415         const gchar *sender;
1416         struct pending_files *p_file;
1417
1418         DBG("");
1419
1420         sender = g_dbus_method_invocation_get_sender(invocation);
1421
1422         g_variant_get(parameters, "(so)", &file_name, &agent);
1423
1424         DBG("file_name = %s, agent = %s", file_name, agent);
1425
1426         if (agent == NULL || file_name == NULL) {
1427                 comms_error_invalid_args(invocation);
1428                 return;
1429         }
1430
1431         p_file = create_pending_files(sender, agent, file_name);
1432         if (p_file)
1433                 pending_push_data = g_list_append(pending_push_data, p_file);
1434
1435         g_dbus_method_invocation_return_value(invocation, NULL);
1436 }
1437
1438 static void send_file_handler(GDBusConnection *connection,
1439                                 GVariant *parameters,
1440                                 GDBusMethodInvocation *invocation,
1441                                 gpointer user_data)
1442 {
1443         struct opp_push_data *data;
1444         gchar *address;
1445         const gchar *agent;
1446         const gchar *sender;
1447         struct agent *client_agent;
1448         guint32 pid = 0;
1449
1450         DBG("");
1451
1452         sender = g_dbus_method_invocation_get_sender(invocation);
1453         g_variant_get(parameters, "(so)", &address, &agent);
1454
1455         DBG("sender = %s", sender);
1456
1457         pid = get_connection_p_id(connection, sender);
1458
1459         if (address == NULL) {
1460                 comms_error_invalid_args(invocation);
1461                 return;
1462         }
1463
1464         if (find_pending_files(sender, agent) == FALSE)
1465                 return comms_error_not_available(invocation);
1466
1467         if (relay_client_agent == NULL) {
1468                 relay_client_agent =
1469                         create_relay_client_agent(connection, sender,
1470                                                 address, agent, pid);
1471                 if (!relay_client_agent)
1472                         return comms_error_not_available(invocation);
1473         } else if (g_strcmp0(relay_client_agent->owner, sender) != 0) {
1474                 client_agent = find_agent(agent_list, sender, agent);
1475                 if (!client_agent) {
1476                         client_agent =
1477                                 create_relay_client_agent(connection, sender,
1478                                                         address, agent, pid);
1479                         if (!client_agent)
1480                                 return comms_error_not_available(invocation);
1481                         agent_list = g_list_append(agent_list, client_agent);
1482                 }
1483                 return comms_error_in_progress(invocation);
1484         } else
1485                 return comms_error_in_progress(invocation);
1486
1487         data = g_new0(struct opp_push_data, 1);
1488         if (data == NULL) {
1489                 ERROR("no memory");
1490                 return;
1491         }
1492
1493         data->address = address;
1494         data->invocation = invocation;
1495         data->invocation_useable = TRUE;
1496
1497         obex_create_session(address, OBEX_OPP, session_state_cb, data);
1498 }
1499
1500 static void add_notify(GDBusConnection *connection,
1501                                 GVariant *parameters,
1502                                 GDBusMethodInvocation *invocation,
1503                                 gpointer user_data)
1504 {
1505         const gchar *sender;
1506         gchar *path;
1507
1508         DBG("+");
1509
1510         if (!relay_agent) {
1511                 comms_error_not_available(invocation);
1512                 return;
1513         }
1514
1515         sender = g_dbus_method_invocation_get_sender(invocation);
1516
1517         if (g_strcmp0(relay_agent->owner, sender) != 0) {
1518                 comms_error_not_available(invocation);
1519                 return;
1520         }
1521
1522         g_variant_get(parameters, "(s)", &path);
1523
1524         obex_transfer_set_notify(path, transfer_server_watched_cb, NULL);
1525
1526         g_dbus_method_invocation_return_value(invocation, NULL);
1527
1528         DBG("-");
1529 }
1530
1531 static void cancel_transfer_handler(GDBusConnection *connection,
1532                                 GVariant *parameters,
1533                                 GDBusMethodInvocation *invocation,
1534                                 gpointer user_data)
1535 {
1536         const gchar *sender;
1537         gchar *name;
1538         guint transfer_id, agent_id = 0;
1539
1540         DBG("");
1541
1542         if (!relay_agent) {
1543                 comms_error_not_available(invocation);
1544                 return;
1545         }
1546
1547         sender = g_dbus_method_invocation_get_sender(invocation);
1548
1549         if (g_strcmp0(relay_agent->owner, sender) != 0) {
1550                 comms_error_not_available(invocation);
1551                 return;
1552         }
1553
1554         g_variant_get(parameters, "(i)", &transfer_id);
1555
1556         if (relay_agent && relay_agent->transfer_path)
1557                 agent_id = obex_get_transfer_id(
1558                         relay_agent->transfer_path, OBEX_SERVER);
1559         else {
1560                 comms_error_not_available(invocation);
1561                 return;
1562         }
1563
1564         if (transfer_id == agent_id) {
1565                 name = obex_transfer_get_property_name(
1566                                         relay_agent->transfer_path);
1567                 if (!name)
1568                         name = "";
1569                 obex_transfer_cancel(relay_agent->transfer_path);
1570                 send_pushstatus(relay_agent->address,
1571                         name, 0, transfer_id, OBEX_TRANSFER_CANCELED,
1572                         0, relay_agent->pid);
1573                 obex_transfer_clear_notify(relay_agent->transfer_path);
1574         } else {
1575                 comms_error_not_available(invocation);
1576                 return;
1577         }
1578
1579         g_dbus_method_invocation_return_value(invocation, NULL);
1580 }
1581
1582 static void cancel_all_transfer_handler(GDBusConnection *connection,
1583                                 GVariant *parameters,
1584                                 GDBusMethodInvocation *invocation,
1585                                 gpointer user_data)
1586 {
1587         const gchar *sender;
1588         struct pending_files *p_file;
1589         guint transfer_id;
1590         GList *list, *next;
1591
1592         DBG("+");
1593
1594         if (!relay_client_agent) {
1595                 comms_error_not_available(invocation);
1596                 return;
1597         }
1598
1599         sender = g_dbus_method_invocation_get_sender(invocation);
1600
1601         if (g_strcmp0(relay_client_agent->owner, sender) != 0) {
1602                 comms_error_not_available(invocation);
1603                 return;
1604         }
1605
1606         if (!pending_p_list || !g_list_length(pending_p_list))
1607                 return g_dbus_method_invocation_return_value(
1608                                                 invocation, NULL);
1609
1610         for (list = g_list_first(pending_p_list); list; list = next) {
1611                 p_file = list->data;
1612                 next = g_list_next(list);
1613
1614                 if (p_file == NULL)
1615                         continue;
1616
1617                 if (p_file->path)
1618                         obex_transfer_cancel(p_file->path);
1619         }
1620
1621         if (relay_client_agent) {
1622                 obex_session_remove_session(
1623                                         relay_client_agent->session);
1624
1625                 for (list = g_list_first(pending_p_list); list; list = next) {
1626                         p_file = list->data;
1627                         next = g_list_next(list);
1628
1629                         if (p_file == NULL)
1630                                 continue;
1631
1632                         if (p_file->path) {
1633                                 transfer_id = obex_get_transfer_id(
1634                                                 p_file->path, OBEX_CLIENT);
1635                                 send_pushstatus(relay_client_agent->address,
1636                                         p_file->file_name, 0, transfer_id,
1637                                         OBEX_TRANSFER_CANCELED, 0,
1638                                         relay_client_agent->pid);
1639                                 obex_transfer_clear_notify(p_file->path);
1640                         }
1641                         free_pending_files(p_file);
1642                 }
1643
1644                 free_relay_agent(relay_client_agent);
1645                 relay_client_agent = NULL;
1646         }
1647
1648         if (g_list_length(agent_list) > 0) {
1649                 list = g_list_first(agent_list);
1650                 relay_client_agent = list->data;
1651                 agent_list = g_list_remove(agent_list, relay_client_agent);
1652                 obex_create_session(relay_client_agent->address,
1653                                         OBEX_OPP, session_state_cb, NULL);
1654         }
1655
1656         g_dbus_method_invocation_return_value(invocation, NULL);
1657
1658         DBG("-");
1659 }
1660
1661 static void _opp_skeleton_handle_method_call(
1662                                 GDBusConnection *connection,
1663                                 const gchar *sender,
1664                                 const gchar *object_path,
1665                                 const gchar *interface_name,
1666                                 const gchar *method_name,
1667                                 GVariant *parameters,
1668                                 GDBusMethodInvocation *invocation,
1669                                 gpointer user_data)
1670 {
1671         if (g_strcmp0(method_name, "RegisterObexAgent") == 0)
1672                 register_relay_agent_handler(connection,
1673                                                 parameters,
1674                                                 invocation,
1675                                                 user_data);
1676         else if (g_strcmp0(method_name, "UnregisterObexAgent") == 0)
1677                 unregister_relay_agent_handler(connection,
1678                                                 parameters,
1679                                                 invocation,
1680                                                 user_data);
1681         else if (g_strcmp0(method_name, "SendFile") == 0)
1682                 send_file_handler(connection, parameters,
1683                                         invocation, user_data);
1684         else if (g_strcmp0(method_name, "AddFile") == 0)
1685                 add_file_handler(connection, parameters,
1686                                         invocation, user_data);
1687         else if (g_strcmp0(method_name, "RemoveFiles") == 0)
1688                 remove_file_handler(connection, parameters,
1689                                         invocation, user_data);
1690         else if (g_strcmp0(method_name, "CancelTransfer") == 0)
1691                 cancel_transfer_handler(connection, parameters,
1692                                         invocation, user_data);
1693         else if (g_strcmp0(method_name, "CancelAllTransfer") == 0)
1694                 cancel_all_transfer_handler(connection, parameters,
1695                                         invocation, user_data);
1696         else if (g_strcmp0(method_name, "AddNotify") == 0)
1697                 add_notify(connection, parameters,
1698                                         invocation, user_data);
1699         else
1700                 ERROR("Unknown method");
1701
1702
1703 static const GDBusInterfaceVTable _opp_skeleton_vtable =
1704 {
1705         _opp_skeleton_handle_method_call,
1706         NULL,
1707         NULL
1708 };
1709
1710 static GDBusInterfaceVTable *opp_skeleton_get_vtable(
1711                                         GDBusInterfaceSkeleton *skeleton)
1712 {
1713         return (GDBusInterfaceVTable *) &_opp_skeleton_vtable;
1714 }
1715
1716 static GVariant *opp_skeleton_get_properties(
1717                                 GDBusInterfaceSkeleton *_skeleton)
1718 {
1719         GVariantBuilder builder;
1720
1721         DBG("");
1722
1723         g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
1724
1725         return g_variant_builder_end (&builder);
1726 }
1727
1728 static void opp_skeleton_class_init(OppSkeletonClass *klass)
1729 {
1730         GObjectClass *gobject_class;
1731         GDBusInterfaceSkeletonClass *skeleton_class;
1732
1733         DBG("");
1734
1735         gobject_class = G_OBJECT_CLASS(klass);
1736         gobject_class->finalize = opp_skeleton_finalize;
1737
1738         skeleton_class = G_DBUS_INTERFACE_SKELETON_CLASS(klass);
1739
1740         skeleton_class->get_info = opp_skeleton_get_info;
1741         skeleton_class->get_vtable = opp_skeleton_get_vtable;
1742         skeleton_class->get_properties = opp_skeleton_get_properties;
1743 }
1744
1745 OppSkeleton *bt_service_opp_new(void)
1746 {
1747         DBG("");
1748         return g_object_new(TYPE_OPP_SKELETON, NULL);
1749 }
1750
1751 static void obex_agent_added_cb(void *user_data)
1752 {
1753         GDBusConnection *connection = user_data;
1754
1755         obex_agent_unset_agent_added();
1756
1757         if (create_opp_agent(session_connection) == FALSE) {
1758                 g_object_unref(session_connection);
1759                 g_object_unref(bt_opp);
1760                 bt_opp = NULL;
1761
1762                 return;
1763         }
1764
1765         obex_agent_register_agent(OPP_AGENT_PATH,
1766                                 register_obex_agent_cb,
1767                                 connection);
1768 }
1769
1770 void bt_service_opp_init(GDBusObjectSkeleton *gdbus_object_skeleton,
1771                                                 GDBusConnection *connection)
1772 {
1773         GError *error = NULL;
1774         int opp_startup;
1775
1776         DBG("");
1777
1778         if (bt_opp)
1779                 return;
1780
1781         bt_object_skeleton = gdbus_object_skeleton;
1782
1783         session_connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
1784         if (session_connection == NULL) {
1785                 ERROR("%s", error->message);
1786
1787                 g_error_free(error);
1788                 return;
1789         }
1790
1791         bt_opp = bt_service_opp_new();
1792
1793         opp_startup = obex_agent_get_agent();
1794         if (!opp_startup) {
1795                 obex_agent_set_agent_added(obex_agent_added_cb,
1796                                                 connection);
1797
1798                 return;
1799         }
1800
1801         if (create_opp_agent(session_connection) == FALSE) {
1802                 g_object_unref(session_connection);
1803                 g_object_unref(bt_opp);
1804                 bt_opp = NULL;
1805
1806                 return;
1807         }
1808
1809         obex_agent_register_agent(OPP_AGENT_PATH,
1810                                 register_obex_agent_cb,
1811                                 connection);
1812
1813 #ifdef TIZEN_3
1814         ERROR("popups app registers the opp agent here");
1815         struct opp_context *context;
1816
1817         context = g_new0(struct opp_context, 1);
1818         if (context == NULL) {
1819                 ERROR("no memroy");
1820                 return;
1821         }
1822         context->method_name = "RegisterOppAgent";
1823
1824         vertical_notify_bt_opp_agent_on(context);
1825
1826         g_free(context);
1827 #endif
1828 }
1829
1830 void bt_service_opp_deinit(void)
1831 {
1832         GDBusConnection *connection;
1833
1834         DBG("");
1835
1836         if (bt_opp == NULL)
1837                 return;
1838
1839         connection = g_dbus_interface_skeleton_get_connection(
1840                                 G_DBUS_INTERFACE_SKELETON(bt_opp));
1841
1842         obex_agent_unregister_agent(OPP_AGENT_PATH,
1843                                 unregister_obex_agent_cb,
1844                                 connection);
1845 }