4 * Copyright (c) 2013-2014 Intel Corporation.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <sys/param.h>
26 #include <gio/gunixfdlist.h>
29 #include "comms_error.h"
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"
38 #define FILENAME_LEN 100
39 #define ADDRESS_LEN 18
41 #define CONTEXT_LEN 28
43 struct user_privileges {
44 char address[ADDRESS_LEN];
48 G_DEFINE_TYPE(OppSkeleton, opp_skeleton,
49 G_TYPE_DBUS_INTERFACE_SKELETON);
51 static void opp_skeleton_init(OppSkeleton *skeleton)
58 static void opp_skeleton_finalize(GObject *object)
65 static const GDBusMethodInfo * const _method_info_pointers[] =
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),
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),
98 static const GDBusInterfaceInfo _opp_interface_info =
101 (gchar *) "org.tizen.comms.opp",
102 (GDBusMethodInfo **) &_method_info_pointers,
104 (GDBusPropertyInfo **) &_opp_property_info_pointers,
108 static GDBusInterfaceInfo *opp_skeleton_get_info(
109 GDBusInterfaceSkeleton *skeleton)
111 return (GDBusInterfaceInfo *) &_opp_interface_info;
118 gchar *transfer_path;
126 struct pending_files {
135 GVariant *parameters;
136 GDBusMethodInvocation *invocation;
140 struct opp_push_data {
142 GDBusMethodInvocation *invocation;
143 gboolean invocation_useable;
146 struct agent_reply_data {
147 GDBusConnection *connection;
148 GDBusMethodInvocation *invocation;
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;
161 static GList *agent_list;
162 static GList *agent_server_list;
163 static GList *pending_push_data;
164 static GList *pending_p_list;
166 #define OBEX_ERROR_INTERFACE "org.bluez.obex.Error"
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,
176 static struct agent *find_agent(GList *agent_l,
177 const char *sender, const char *path);
179 static void bt_opp_register_dbus_interface(OppSkeleton *skeleton,
180 GDBusConnection *connection)
182 GDBusInterfaceSkeleton *opp_interface;
184 opp_interface = G_DBUS_INTERFACE_SKELETON(skeleton);
186 g_dbus_object_skeleton_add_interface(bt_object_skeleton,
190 static void bt_opp_unregister_dbus_interface()
192 GDBusInterfaceSkeleton *opp_interface;
194 opp_interface = G_DBUS_INTERFACE_SKELETON(bt_opp);
195 g_dbus_object_skeleton_remove_interface(bt_object_skeleton,
199 static void destruct_opp_agent(GDBusConnection *connection)
201 if (opp_agent_dbus_id > 0)
202 g_dbus_connection_unregister_object(connection,
205 g_dbus_node_info_unref(opp_introspection_data);
208 static guint32 get_connection_p_id(GDBusConnection *connection,
211 GError *error = NULL;
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);
225 if (pidvalue == NULL) {
226 DBG("GetConnectionUnixUser: %s", error->message);
231 g_variant_get(pidvalue, "(u)", &pid);
232 g_variant_unref(pidvalue);
237 static guint32 get_connection_user_id(GDBusConnection *connection,
240 GError *error = NULL;
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);
254 if (uidvalue == NULL) {
255 DBG("GetConnectionUnixUser: %s", error->message);
260 g_variant_get(uidvalue, "(u)", &uid);
261 g_variant_unref(uidvalue);
266 static void handle_pushstatus(GVariant *parameters)
268 GDBusConnection *connection;
271 connection = g_dbus_interface_skeleton_get_connection(
272 G_DBUS_INTERFACE_SKELETON(bt_opp));
274 g_dbus_connection_emit_signal(connection, NULL,
275 "/org/tizen/comms/bluetooth",
276 "org.freedesktop.DBus.Properties",
284 void send_pushstatus(char *destination, const char *name, guint64 size,
285 guint transfer_id, enum transfer_state state,
286 double percent, guint32 pid)
288 GVariant *parameters;
289 GVariantBuilder *builder;
294 builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
296 val = g_variant_new("s", destination);
298 val = g_variant_new("s", "");
299 g_variant_builder_add(builder, "{sv}", "address", val);
301 val = g_variant_new("s", name);
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);
316 parameters = g_variant_ref_sink(g_variant_new("(sa{sv}as)",
317 "org.tizen.comms.opp",
320 handle_pushstatus(parameters);
323 static void transfer_watched_cb(
324 const char *transfer_path,
325 enum transfer_state state,
332 struct pending_files *p_file = data;
337 transfer_id = obex_get_transfer_id(transfer_path, OBEX_CLIENT);
339 DBG("state: %d, %d, %s, %ju", state, transfer_id,
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;
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);
360 if (state == OBEX_TRANSFER_COMPLETE) {
361 vertical_notify_bt_transfer(100);
362 relay_client_agent->number--;
366 if (state == OBEX_TRANSFER_ACTIVE) {
369 DBG("transferred %ju, size %ju", transferred, size);
370 percent = (double) transferred * 100 / size;
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);
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();
390 pending_p_list = g_list_remove(pending_p_list, p_file);
391 free_pending_files(p_file);
395 static void transfer_server_watched_cb(
396 const char *transfer_path,
397 enum transfer_state state,
408 transfer_id = obex_get_transfer_id(transfer_path, OBEX_SERVER);
410 if (relay_agent && !relay_agent->transfer_path)
411 relay_agent->transfer_path = g_strdup(transfer_path);
413 DBG("state: %d, %d, %s, %ju", state, transfer_id,
416 if (state == OBEX_TRANSFER_ERROR) {
417 vertical_notify_bt_transfer(0);
419 send_pushstatus(relay_agent->address,
420 name, size, transfer_id, state, 0,
422 g_free(relay_agent->transfer_path);
423 relay_agent->transfer_path = NULL;
428 if (state == OBEX_TRANSFER_QUEUED) {
429 vertical_notify_bt_transfer(0);
431 send_pushstatus(relay_agent->address,
432 name, size, transfer_id, state, 0,
437 if (state == OBEX_TRANSFER_COMPLETE) {
438 vertical_notify_bt_transfer(100);
440 send_pushstatus(relay_agent->address,
441 name, size, transfer_id, state, 100,
443 g_free(relay_agent->transfer_path);
444 relay_agent->transfer_path = NULL;
449 if (state == OBEX_TRANSFER_ACTIVE) {
452 DBG("transferred %ju, size %ju", transferred, size);
453 percent = (double) transferred * 100 / size;
455 vertical_notify_bt_transfer(percent);
457 send_pushstatus(relay_agent->address,
458 name, size, transfer_id, state, percent,
464 static void register_obex_agent_cb(enum bluez_error_type type, void *user_data)
466 GDBusConnection *connection = user_data;
468 if (type != ERROR_NONE) {
469 destruct_opp_agent(session_connection);
471 g_object_unref(session_connection);
473 g_object_unref(bt_opp);
479 bt_opp_register_dbus_interface(bt_opp, connection);
482 static void unregister_obex_agent_cb(enum bluez_error_type type, void *user_data)
484 if (type != ERROR_NONE)
485 ERROR("unregister obex agent failed :%d", type);
487 destruct_opp_agent(session_connection);
489 bt_opp_unregister_dbus_interface();
491 g_object_unref(session_connection);
492 g_object_unref(bt_opp);
496 static void agent_request_release_reply(GObject *source_object,
497 GAsyncResult *result,
501 GError *error = NULL;
502 struct agent_reply_data *reply_data = user_data;
504 ret = g_dbus_connection_call_finish(reply_data->connection,
507 g_dbus_method_invocation_return_value(reply_data->invocation, ret);
512 static void authorize_push_reply(GObject *source_object,
513 GAsyncResult *result,
517 GError *error = NULL;
518 struct agent_reply_data *reply_data = user_data;
520 ret = g_dbus_connection_call_finish(reply_data->connection,
524 WARN("%s", error->message);
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",
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",
537 comms_error_failed(reply_data->invocation, "Failed");
543 g_dbus_method_invocation_return_value(reply_data->invocation, ret);
548 static void agent_request_cancel_reply(GObject *source_object,
549 GAsyncResult *result,
553 GError *error = NULL;
554 struct agent_reply_data *reply_data = user_data;
556 ret = g_dbus_connection_call_finish(reply_data->connection,
559 g_dbus_method_invocation_return_value(reply_data->invocation, ret);
564 static const gchar opp_introspection_xml[] =
566 " <interface name='org.bluez.obex.Agent1'>"
567 " <method name='Release'>"
569 " <method name='AuthorizePush'>"
570 " <arg type='o' name='transfer' direction='in'/>"
571 " <arg type='s' direction='out'/>"
573 " <method name='Cancel'>"
578 static void handle_release(GDBusConnection *connection,
579 GVariant *parameters,
580 GDBusMethodInvocation *invocation,
583 struct agent_reply_data *reply_data;
587 reply_data = g_new0(struct agent_reply_data, 1);
589 reply_data->connection = connection;
590 reply_data->invocation = invocation;
592 g_dbus_connection_call(connection,
594 relay_agent->object_path,
599 G_DBUS_CALL_FLAGS_NONE,
601 agent_request_release_reply,
605 static int get_privileges_uid(gchar *address)
607 char file[FILENAME_LEN];
608 char context[CONTEXT_LEN];
609 char *path = getenv("HOME");
611 struct user_privileges *privileges = NULL;
619 sprintf(file, "%s/.bt_userprivileges", path);
621 fd = open(file, O_RDONLY, S_IRUSR | S_IWUSR);
628 if (fstat(fd, &st) < 0) {
630 DBG("privileges context error");
635 lseek(fd, 0, SEEK_SET);
637 while (len >= CONTEXT_LEN) {
638 memset(context, 0, CONTEXT_LEN);
639 ret = read(fd, context, CONTEXT_LEN-2);
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");
651 return privileges_uid;
654 lseek(fd, 2, SEEK_CUR);
662 static struct agent *find_server_agent(guint32 uid)
667 DBG("uid = %d", uid);
669 if (agent_server_list == NULL)
672 for (list = g_list_first(agent_server_list);
674 next = g_list_next(list);
677 if (agent && (agent->uid == uid))
684 static void handle_authorize_push(GDBusConnection *connection,
685 GVariant *parameters,
686 GDBusMethodInvocation *invocation,
689 struct agent_reply_data *reply_data;
690 gchar *transfer_path = NULL;
691 gchar *destination = NULL;
694 guint transfer_id = 0;
697 struct agent *agent = NULL;
701 reply_data = g_new0(struct agent_reply_data, 1);
703 reply_data->connection = connection;
704 reply_data->invocation = invocation;
706 g_variant_get(parameters, "(o)", &transfer_path);
708 obex_transfer_get_property_size(transfer_path, &size);
709 name = obex_transfer_get_property_name(transfer_path);
712 destination = obex_transfer_get_property_destination(transfer_path);
715 transfer_id = obex_get_transfer_id(transfer_path, OBEX_SERVER);
717 uid = get_privileges_uid(destination);
718 DBG("destination = %s, uid = %d", destination, uid);
721 agent = find_server_agent(uid);
726 param = g_variant_new("(sssti)",
727 destination, name, transfer_path, size, transfer_id);
729 g_dbus_connection_call(connection,
731 relay_agent->object_path,
735 g_variant_type_new("(s)"),
736 G_DBUS_CALL_FLAGS_NONE,
738 authorize_push_reply,
742 static void handle_cancel(GDBusConnection *connection,
743 GVariant *parameters,
744 GDBusMethodInvocation *invocation,
747 struct agent_reply_data *reply_data;
751 reply_data = g_new0(struct agent_reply_data, 1);
753 reply_data->connection = connection;
754 reply_data->invocation = invocation;
756 g_dbus_connection_call(connection,
758 relay_agent->object_path,
763 G_DBUS_CALL_FLAGS_NONE,
765 agent_request_cancel_reply,
769 static void handle_opp_context(GDBusConnection *connection,
770 struct opp_context *context)
772 gchar *method_name = context->method_name;
773 if (g_strcmp0(method_name, "Release") == 0)
774 handle_release(connection,
778 else if (g_strcmp0(method_name, "AuthorizePush") == 0)
779 handle_authorize_push(connection,
783 else if (g_strcmp0(method_name, "Cancel") == 0)
784 handle_cancel(connection,
789 WARN("Unknown method %s", method_name);
792 static struct opp_context *create_opp_context(const gchar *method_name,
793 GVariant *parameters,
794 GDBusMethodInvocation *invocation,
797 struct opp_context *context;
799 context = g_new0(struct opp_context, 1);
800 if (context == NULL) {
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;
814 static void free_opp_context(gpointer user_data)
816 struct opp_context *context = user_data;
818 g_free(context->method_name);
819 g_variant_unref(context->parameters);
824 static gboolean relay_agent_timeout_cb(gpointer user_data)
828 comms_error_failed(opp_context->invocation, "Relay agent timeout");
830 free_opp_context(opp_context);
837 static void handle_opp_agent_method_call(GDBusConnection *connection,
839 const gchar *object_path,
840 const gchar *interface,
841 const gchar *method_name,
842 GVariant *parameters,
843 GDBusMethodInvocation *invocation,
846 opp_context = create_opp_context(method_name, parameters,
847 invocation, user_data);
850 GDBusConnection *system_connection;
852 system_connection = g_dbus_interface_skeleton_get_connection(
853 G_DBUS_INTERFACE_SKELETON(bt_opp));
855 handle_opp_context(system_connection, opp_context);
857 free_opp_context(opp_context);
864 vertical_notify_bt_opp_agent_on(NULL);
866 relay_agent_timeout_id = g_timeout_add(500,
867 relay_agent_timeout_cb, NULL);
870 static const GDBusInterfaceVTable opp_agent_vtable =
872 handle_opp_agent_method_call,
877 static gboolean create_opp_agent(GDBusConnection *connection)
879 opp_introspection_data = g_dbus_node_info_new_for_xml(
880 opp_introspection_xml, NULL);
881 if (opp_introspection_data == NULL)
884 opp_agent_dbus_id = g_dbus_connection_register_object(connection,
886 opp_introspection_data->interfaces[0],
889 if (opp_agent_dbus_id < 0) {
890 ERROR("Register OPP Agent Failed");
897 static struct pending_files *create_pending_files(const gchar *sender,
898 const gchar *path, const gchar *file_name)
900 struct pending_files *p_file;
904 p_file = g_new0(struct pending_files, 1);
905 if (p_file == NULL) {
910 p_file->owner = g_strdup(sender);
911 p_file->object_path = g_strdup(path);
912 p_file->file_name = g_strdup(file_name);
917 static void free_pending_files(struct pending_files *p_file)
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);
931 g_free(p_file->path);
938 static void free_all_pending_files(void)
941 struct pending_files *p_file;
945 if (!pending_p_list ||
946 g_list_length(pending_p_list) == 0)
949 for (list = g_list_first(pending_p_list); list; list = next) {
950 next = g_list_next(list);
952 pending_p_list = g_list_remove(pending_p_list, p_file);
954 free_pending_files(p_file);
957 pending_p_list = NULL;
962 static void free_remove_relay_agent(void)
968 if (relay_client_agent) {
969 obex_session_remove_session(
970 relay_client_agent->session);
971 free_relay_agent(relay_client_agent);
973 relay_client_agent = NULL;
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);
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)
991 agent = g_new0(struct agent, 1);
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;
1007 static void free_relay_agent(struct agent *agent)
1013 g_free(agent->owner);
1014 if (agent->object_path)
1015 g_free(agent->object_path);
1017 g_free(agent->session);
1018 if (agent->transfer_path)
1019 g_free(agent->transfer_path);
1024 static void relay_agent_disconnected(GDBusConnection *connection,
1025 const gchar *name, gpointer user_data)
1027 struct agent *agent = (struct agent *)user_data;
1034 agent_server_list = g_list_remove(agent_server_list, agent);
1037 if (!g_strcmp0(agent->object_path, relay_agent->object_path) &&
1038 !g_strcmp0(agent->owner, relay_agent->owner)) {
1040 next = g_list_last(agent_server_list);
1042 relay_agent = next->data;
1047 free_relay_agent(agent);
1050 static void relay_client_agent_disconnected(GDBusConnection *connection,
1051 const gchar *name, gpointer user_data)
1055 if (!relay_client_agent)
1058 free_relay_agent(relay_client_agent);
1060 relay_client_agent = NULL;
1063 static void register_relay_agent_handler(GDBusConnection *connection,
1064 GVariant *parameters,
1065 GDBusMethodInvocation *invocation,
1068 const gchar *sender;
1070 guint relay_agent_watch_id;
1072 struct agent *agent = NULL;
1076 g_variant_get(parameters, "(o)", &agent_path);
1077 if (agent_path == NULL)
1078 return comms_error_invalid_args(invocation);
1080 sender = g_dbus_method_invocation_get_sender(invocation);
1081 uid = get_connection_user_id(connection, sender);
1083 agent = find_server_agent(uid);
1085 return comms_error_already_done(invocation);
1087 pid = get_connection_p_id(connection, sender);
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,
1095 relay_agent = create_relay_agent(sender, agent_path, NULL, pid,
1096 uid, relay_agent_watch_id);
1098 agent_server_list = g_list_append(agent_server_list, relay_agent);
1100 if (relay_agent_timeout_id > 0) {
1101 g_source_remove(relay_agent_timeout_id);
1103 relay_agent_timeout_id = 0;
1106 g_dbus_method_invocation_return_value(invocation, NULL);
1111 handle_opp_context(connection, opp_context);
1113 free_opp_context(opp_context);
1118 static void unregister_relay_agent_handler(GDBusConnection *connection,
1119 GVariant *parameters,
1120 GDBusMethodInvocation *invocation,
1124 const gchar *sender;
1125 struct agent *agent;
1129 if (relay_agent == NULL)
1130 return comms_error_does_not_exist(invocation);
1132 sender = g_dbus_method_invocation_get_sender(invocation);
1134 g_variant_get(parameters, "(o)", &agent_path);
1135 if (agent_path == NULL)
1136 return comms_error_invalid_args(invocation);
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);
1144 agent_server_list = g_list_remove(agent_server_list, agent);
1147 if (!g_strcmp0(agent_path, relay_agent->object_path) &&
1148 !g_strcmp0(sender, relay_agent->owner)) {
1150 next = g_list_last(agent_server_list);
1152 relay_agent = next->data;
1157 g_dbus_method_invocation_return_value(invocation, NULL);
1161 free_relay_agent(agent);
1164 char *get_failed_content(const gchar *error_message)
1166 const gchar *title = "org.bluez.obex.Error.Failed: ";
1167 gchar *error_str = g_strrstr(error_message, title);
1169 if (error_str == NULL)
1172 return error_str + strlen(title);
1175 static void handle_error_message(GDBusMethodInvocation *invocation,
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);
1183 return comms_error_failed(invocation, info);
1185 WARN("Unknown error %s", error_msg);
1188 static void transfer_state_cb(
1189 const char *transfer_path,
1190 enum transfer_state state,
1193 guint64 transferred,
1197 struct pending_files *p_file = data;
1199 DBG("transfer path %s", transfer_path);
1200 DBG("state %d", state);
1203 DBG("error = %s", error_msg);
1204 free_all_pending_files();
1205 free_remove_relay_agent();
1209 if (state == OBEX_TRANSFER_QUEUED) {
1211 p_file->path = g_strdup(transfer_path);
1212 pending_p_list = g_list_append(pending_p_list, p_file);
1214 obex_transfer_set_notify((char *)transfer_path,
1215 transfer_watched_cb, p_file);
1219 static void send_pending_push_data(void)
1221 struct pending_files *p_file;
1222 gboolean is_send = FALSE;
1227 if (g_list_length(pending_push_data) == 0)
1230 for (list = g_list_first(pending_push_data); list; list = next) {
1231 next = g_list_next(list);
1232 p_file = list->data;
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,
1241 transfer_state_cb, p_file);
1243 g_list_remove(pending_push_data, p_file);
1248 if (is_send == FALSE)
1249 free_remove_relay_agent();
1252 static void session_state_cb(const gchar *session_id,
1253 const gchar *session,
1254 enum session_state state,
1258 gchar *name = "OBEX_TRANSFER_QUEUED";
1260 guint transfer_id = 0;
1261 struct opp_push_data *push_data = user_data;
1263 DBG("%s", error_msg);
1266 DBG("error = %s", error_msg);
1268 handle_error_message(
1269 push_data->invocation, error_msg);
1272 free_remove_relay_agent();
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);
1281 DBG("session = %s", session);
1282 relay_client_agent->session = g_strdup(session);
1284 if (g_list_length(pending_push_data) > 0)
1285 send_pending_push_data();
1289 g_dbus_method_invocation_return_value(
1290 push_data->invocation, NULL);
1295 static struct agent *find_agent(GList *agent_l,
1296 const char *sender, const char *path)
1298 struct agent *agent;
1301 DBG("sender = %s, path = %s", sender, path);
1303 if (agent_l == NULL)
1306 for (list = g_list_first(agent_l); list; list = next) {
1307 next = g_list_next(list);
1311 if (agent && !g_strcmp0(agent->owner, sender)
1312 && !g_strcmp0(agent->object_path, path))
1319 static gboolean find_pending_files(const char *sender, const char *path)
1321 struct pending_files *p_file;
1324 DBG("sender = %s, path = %s", sender, path);
1326 if (pending_push_data == NULL)
1329 for (list = g_list_first(pending_push_data); list; list = next) {
1330 next = g_list_next(list);
1332 p_file = list->data;
1334 if (p_file && !g_strcmp0(p_file->owner, sender)
1335 && !g_strcmp0(p_file->object_path, path))
1342 static struct agent *create_relay_client_agent(GDBusConnection *connection,
1343 const gchar *sender, const gchar *address,
1344 const gchar *agent, guint32 pid)
1346 guint relay_agent_watch_id;
1347 struct agent *client_agent;
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,
1355 client_agent = create_relay_agent(sender, agent, address, pid, 0,
1356 relay_agent_watch_id);
1358 return client_agent;
1362 static void remove_file_handler(GDBusConnection *connection,
1363 GVariant *parameters,
1364 GDBusMethodInvocation *invocation,
1367 struct agent *agent;
1368 const gchar *sender, *path;
1369 struct pending_files *p_file;
1372 sender = g_dbus_method_invocation_get_sender(invocation);
1374 DBG("sender = %s", sender);
1376 if (agent_list == NULL)
1377 return comms_error_failed(invocation, "Failed");
1379 g_variant_get(parameters, "(o)", &path);
1381 for (list = g_list_first(agent_list); list; list = next) {
1382 next = g_list_next(list);
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);
1393 for (list = g_list_first(pending_push_data); list; list = next) {
1394 next = g_list_next(list);
1396 p_file = list->data;
1397 if (p_file && !g_strcmp0(p_file->owner, sender)
1398 && !g_strcmp0(p_file->object_path, path)) {
1400 g_list_remove(pending_push_data, p_file);
1401 free_pending_files(p_file);
1405 return g_dbus_method_invocation_return_value(invocation, NULL);
1408 static void add_file_handler(GDBusConnection *connection,
1409 GVariant *parameters,
1410 GDBusMethodInvocation *invocation,
1413 const gchar *file_name;
1415 const gchar *sender;
1416 struct pending_files *p_file;
1420 sender = g_dbus_method_invocation_get_sender(invocation);
1422 g_variant_get(parameters, "(so)", &file_name, &agent);
1424 DBG("file_name = %s, agent = %s", file_name, agent);
1426 if (agent == NULL || file_name == NULL) {
1427 comms_error_invalid_args(invocation);
1431 p_file = create_pending_files(sender, agent, file_name);
1433 pending_push_data = g_list_append(pending_push_data, p_file);
1435 g_dbus_method_invocation_return_value(invocation, NULL);
1438 static void send_file_handler(GDBusConnection *connection,
1439 GVariant *parameters,
1440 GDBusMethodInvocation *invocation,
1443 struct opp_push_data *data;
1446 const gchar *sender;
1447 struct agent *client_agent;
1452 sender = g_dbus_method_invocation_get_sender(invocation);
1453 g_variant_get(parameters, "(so)", &address, &agent);
1455 DBG("sender = %s", sender);
1457 pid = get_connection_p_id(connection, sender);
1459 if (address == NULL) {
1460 comms_error_invalid_args(invocation);
1464 if (find_pending_files(sender, agent) == FALSE)
1465 return comms_error_not_available(invocation);
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) {
1477 create_relay_client_agent(connection, sender,
1478 address, agent, pid);
1480 return comms_error_not_available(invocation);
1481 agent_list = g_list_append(agent_list, client_agent);
1483 return comms_error_in_progress(invocation);
1485 return comms_error_in_progress(invocation);
1487 data = g_new0(struct opp_push_data, 1);
1493 data->address = address;
1494 data->invocation = invocation;
1495 data->invocation_useable = TRUE;
1497 obex_create_session(address, OBEX_OPP, session_state_cb, data);
1500 static void add_notify(GDBusConnection *connection,
1501 GVariant *parameters,
1502 GDBusMethodInvocation *invocation,
1505 const gchar *sender;
1511 comms_error_not_available(invocation);
1515 sender = g_dbus_method_invocation_get_sender(invocation);
1517 if (g_strcmp0(relay_agent->owner, sender) != 0) {
1518 comms_error_not_available(invocation);
1522 g_variant_get(parameters, "(s)", &path);
1524 obex_transfer_set_notify(path, transfer_server_watched_cb, NULL);
1526 g_dbus_method_invocation_return_value(invocation, NULL);
1531 static void cancel_transfer_handler(GDBusConnection *connection,
1532 GVariant *parameters,
1533 GDBusMethodInvocation *invocation,
1536 const gchar *sender;
1538 guint transfer_id, agent_id = 0;
1543 comms_error_not_available(invocation);
1547 sender = g_dbus_method_invocation_get_sender(invocation);
1549 if (g_strcmp0(relay_agent->owner, sender) != 0) {
1550 comms_error_not_available(invocation);
1554 g_variant_get(parameters, "(i)", &transfer_id);
1556 if (relay_agent && relay_agent->transfer_path)
1557 agent_id = obex_get_transfer_id(
1558 relay_agent->transfer_path, OBEX_SERVER);
1560 comms_error_not_available(invocation);
1564 if (transfer_id == agent_id) {
1565 name = obex_transfer_get_property_name(
1566 relay_agent->transfer_path);
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);
1575 comms_error_not_available(invocation);
1579 g_dbus_method_invocation_return_value(invocation, NULL);
1582 static void cancel_all_transfer_handler(GDBusConnection *connection,
1583 GVariant *parameters,
1584 GDBusMethodInvocation *invocation,
1587 const gchar *sender;
1588 struct pending_files *p_file;
1594 if (!relay_client_agent) {
1595 comms_error_not_available(invocation);
1599 sender = g_dbus_method_invocation_get_sender(invocation);
1601 if (g_strcmp0(relay_client_agent->owner, sender) != 0) {
1602 comms_error_not_available(invocation);
1606 if (!pending_p_list || !g_list_length(pending_p_list))
1607 return g_dbus_method_invocation_return_value(
1610 for (list = g_list_first(pending_p_list); list; list = next) {
1611 p_file = list->data;
1612 next = g_list_next(list);
1618 obex_transfer_cancel(p_file->path);
1621 if (relay_client_agent) {
1622 obex_session_remove_session(
1623 relay_client_agent->session);
1625 for (list = g_list_first(pending_p_list); list; list = next) {
1626 p_file = list->data;
1627 next = g_list_next(list);
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);
1641 free_pending_files(p_file);
1644 free_relay_agent(relay_client_agent);
1645 relay_client_agent = NULL;
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);
1656 g_dbus_method_invocation_return_value(invocation, NULL);
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,
1671 if (g_strcmp0(method_name, "RegisterObexAgent") == 0)
1672 register_relay_agent_handler(connection,
1676 else if (g_strcmp0(method_name, "UnregisterObexAgent") == 0)
1677 unregister_relay_agent_handler(connection,
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);
1700 ERROR("Unknown method");
1703 static const GDBusInterfaceVTable _opp_skeleton_vtable =
1705 _opp_skeleton_handle_method_call,
1710 static GDBusInterfaceVTable *opp_skeleton_get_vtable(
1711 GDBusInterfaceSkeleton *skeleton)
1713 return (GDBusInterfaceVTable *) &_opp_skeleton_vtable;
1716 static GVariant *opp_skeleton_get_properties(
1717 GDBusInterfaceSkeleton *_skeleton)
1719 GVariantBuilder builder;
1723 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
1725 return g_variant_builder_end (&builder);
1728 static void opp_skeleton_class_init(OppSkeletonClass *klass)
1730 GObjectClass *gobject_class;
1731 GDBusInterfaceSkeletonClass *skeleton_class;
1735 gobject_class = G_OBJECT_CLASS(klass);
1736 gobject_class->finalize = opp_skeleton_finalize;
1738 skeleton_class = G_DBUS_INTERFACE_SKELETON_CLASS(klass);
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;
1745 OppSkeleton *bt_service_opp_new(void)
1748 return g_object_new(TYPE_OPP_SKELETON, NULL);
1751 static void obex_agent_added_cb(void *user_data)
1753 GDBusConnection *connection = user_data;
1755 obex_agent_unset_agent_added();
1757 if (create_opp_agent(session_connection) == FALSE) {
1758 g_object_unref(session_connection);
1759 g_object_unref(bt_opp);
1765 obex_agent_register_agent(OPP_AGENT_PATH,
1766 register_obex_agent_cb,
1770 void bt_service_opp_init(GDBusObjectSkeleton *gdbus_object_skeleton,
1771 GDBusConnection *connection)
1773 GError *error = NULL;
1781 bt_object_skeleton = gdbus_object_skeleton;
1783 session_connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
1784 if (session_connection == NULL) {
1785 ERROR("%s", error->message);
1787 g_error_free(error);
1791 bt_opp = bt_service_opp_new();
1793 opp_startup = obex_agent_get_agent();
1795 obex_agent_set_agent_added(obex_agent_added_cb,
1801 if (create_opp_agent(session_connection) == FALSE) {
1802 g_object_unref(session_connection);
1803 g_object_unref(bt_opp);
1809 obex_agent_register_agent(OPP_AGENT_PATH,
1810 register_obex_agent_cb,
1814 ERROR("popups app registers the opp agent here");
1815 struct opp_context *context;
1817 context = g_new0(struct opp_context, 1);
1818 if (context == NULL) {
1822 context->method_name = "RegisterOppAgent";
1824 vertical_notify_bt_opp_agent_on(context);
1830 void bt_service_opp_deinit(void)
1832 GDBusConnection *connection;
1839 connection = g_dbus_interface_skeleton_get_connection(
1840 G_DBUS_INTERFACE_SKELETON(bt_opp));
1842 obex_agent_unregister_agent(OPP_AGENT_PATH,
1843 unregister_obex_agent_cb,