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.
27 #define OBEX_NAME "org.bluez.obex"
29 #define OBJECT_MANAGE_PATH "/"
31 #define OBJECT_OBEX_PATH "/org/bluez/obex"
33 #define OBEX_AGENT_INTERFACE "org.bluez.obex.AgentManager1"
35 #define PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
37 #define MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager"
39 #define OBEX_SESSION_INTERFACE "org.bluez.obex.Session1"
41 #define OBEX_TRANSFER_INTERFACE "org.bluez.obex.Transfer1"
43 static GDBusConnection *g_connection;
44 static int g_opp_startup;
45 static GDBusProxy *manager_proxy;
46 static GDBusObjectManager *object_manager;
48 static obex_agent_added_cb_t obex_agent_added_cb;
49 static void *obex_agent_added_cb_data;
51 static GDBusConnection *_obex_get_session_dbus(void)
59 g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
60 if (g_connection == NULL) {
61 DBG("%s", error->message);
68 void obex_agent_set_agent_added(obex_agent_added_cb_t cb, void *user_data)
70 obex_agent_added_cb = cb;
71 obex_agent_added_cb_data = user_data;
74 void obex_agent_unset_agent_added(void)
76 obex_agent_added_cb = NULL;
77 obex_agent_added_cb_data = NULL;
83 GDBusConnection *conn;
86 static void agent_callback(GObject *source_object,
92 enum bluez_error_type error_type = ERROR_NONE;
93 struct agent_data *agent_data = user_data;
97 ret = g_dbus_connection_call_finish(agent_data->conn,
100 error_type = get_error_type(error);
101 ERROR("error = %d", error_type);
105 agent_data->cb(error_type, agent_data->user_data);
112 void obex_agent_register_agent(const char *agent_path,
116 struct agent_data *register_data;
117 GDBusConnection *connection = _obex_get_session_dbus();
121 register_data = g_new0(struct agent_data, 1);
122 if (register_data == NULL) {
127 register_data->cb = cb;
128 register_data->user_data = user_data;
129 register_data->conn = connection;
132 g_dbus_connection_call(connection, "org.bluez.obex",
134 "org.bluez.obex.AgentManager1",
136 g_variant_new("(o)", agent_path),
137 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
138 agent_callback, register_data);
140 ERROR("agent not registered");
143 void obex_agent_unregister_agent(const char *agent_path,
147 struct agent_data *unregister_data;
148 GDBusConnection *connection = _obex_get_session_dbus();
152 unregister_data = g_new0(struct agent_data, 1);
153 if (unregister_data == NULL) {
158 unregister_data->cb = cb;
159 unregister_data->user_data = user_data;
162 g_dbus_connection_call(connection, "org.bluez.obex",
164 "org.bluez.obex.AgentManager1",
166 g_variant_new("(o)", agent_path),
167 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
168 agent_callback, unregister_data);
170 ERROR("agent not registered");
173 static enum transfer_state get_transfer_state_from_string(const char *string)
176 return OBEX_TRANSFER_UNKNOWN;
178 if (!g_strcmp0(string, "queued"))
179 return OBEX_TRANSFER_QUEUED;
181 if (!g_strcmp0(string, "active"))
182 return OBEX_TRANSFER_ACTIVE;
184 if (!g_strcmp0(string, "complete"))
185 return OBEX_TRANSFER_COMPLETE;
187 if (!g_strcmp0(string, "error"))
188 return OBEX_TRANSFER_ERROR;
190 return OBEX_TRANSFER_UNKNOWN;
193 enum transfer_state obex_transfer_get_property_state(const char *path)
200 p_proxy = g_dbus_proxy_new_for_bus_sync(
201 G_BUS_TYPE_SESSION, 0,
205 PROPERTIES_INTERFACE,
209 status = property_get_string(p_proxy,
210 OBEX_TRANSFER_INTERFACE, "Status");
212 g_object_unref(p_proxy);
214 return get_transfer_state_from_string(status);
217 int obex_transfer_get_property_transferred(const char *path,
225 p_proxy = g_dbus_proxy_new_for_bus_sync(
226 G_BUS_TYPE_SESSION, 0,
230 PROPERTIES_INTERFACE,
234 ret = property_get_uint64(p_proxy,
235 OBEX_TRANSFER_INTERFACE, "Transferred", u64);
237 g_object_unref(p_proxy);
242 int obex_transfer_get_property_size(const char *path,
248 DBG("path = %s", path);
249 p_proxy = g_dbus_proxy_new_for_bus_sync(
250 G_BUS_TYPE_SESSION, 0,
254 PROPERTIES_INTERFACE,
258 ret = property_get_uint64(p_proxy,
259 OBEX_TRANSFER_INTERFACE, "Size", u64);
261 g_object_unref(p_proxy);
266 static void parse_object(gpointer data, gpointer user_data)
268 GDBusObject *obj = data;
269 const char *path = g_dbus_object_get_object_path(obj);
272 DBG("object path name %s", path);
274 if (!g_strcmp0(path, OBJECT_OBEX_PATH)) {
275 if (g_opp_startup == 1)
278 if (obex_agent_added_cb)
279 obex_agent_added_cb(obex_agent_added_cb_data);
286 static void interfaces_removed(GVariant *parameters)
291 gchar *parameters_s = g_variant_print(parameters, TRUE);
293 g_variant_get(parameters, "(oas)", &object_path, &iter);
295 DBG("%s", parameters_s);
297 g_free(parameters_s);
299 DBG("%s", object_path);
301 if (!g_strcmp0(object_path, OBJECT_OBEX_PATH))
305 static void interfaces_added(GVariant *parameters)
310 g_variant_get(parameters, "(oa{sa{sv}})", &object_path, NULL);
312 DBG("object %s", object_path);
314 obj = g_dbus_object_manager_get_object(object_manager, object_path);
317 parse_object(obj, NULL);
320 static gboolean handle_interfaces_added(gpointer user_data)
322 GVariant *parameters = user_data;
324 interfaces_added(parameters);
326 g_variant_unref(parameters);
331 static void interfaces_changed(GDBusProxy *proxy,
334 GVariant *parameters,
337 if (!g_strcmp0(signal_name, "InterfacesAdded"))
338 g_idle_add(handle_interfaces_added,
339 g_variant_ref_sink(parameters));
340 if (!g_strcmp0(signal_name, "InterfacesRemoved"))
341 interfaces_removed(parameters);
344 int obex_agent_get_agent(void)
346 return g_opp_startup;
349 int obex_lib_init(void)
355 if (object_manager != NULL)
358 manager_proxy = g_dbus_proxy_new_for_bus_sync(
359 G_BUS_TYPE_SESSION, 0,
366 if (manager_proxy == NULL)
367 ERROR("create manager_proxy error");
369 DBG("manager proxy 0x%p created", manager_proxy);
371 g_signal_connect(manager_proxy,
373 G_CALLBACK(interfaces_changed),
377 object_manager = g_dbus_object_manager_client_new_for_bus_sync(
385 if (object_manager == NULL) {
386 ERROR("create object manager error");
387 /* TODO: define error type */
391 DBG("object manager %p is created", object_manager);
393 obj_list = g_dbus_object_manager_get_objects(object_manager);
395 g_list_foreach(obj_list, parse_object, NULL);
400 static void destruct_obex_object_manager(void)
404 g_object_unref(object_manager);
406 object_manager = NULL;
409 void obex_lib_deinit(void)
414 g_object_unref(manager_proxy);
416 destruct_obex_object_manager();
419 struct obex_session_result {
420 obex_session_state_cb cb;
422 GDBusConnection *conn;
425 static const char *get_obex_target_string(enum obex_target target)
428 case OBEX_TARGET_UNKNOWN:
447 static void create_session_cb(GObject *object,
454 struct obex_session_result *async_node;
457 async_node = user_data;
461 result = g_dbus_connection_call_finish(async_node->conn,
465 ERROR("create session error %s", error->message);
467 async_node->cb(NULL, NULL, OBEX_SESSION_FAILED,
468 async_node->user_data,
469 g_strdup(error->message));
474 g_variant_get(result, "(o)", &session);
476 DBG("Sesseion created %s", session);
478 async_node->cb(NULL, session, OBEX_SESSION_CREATED,
479 async_node->user_data, NULL);
483 g_variant_unref(result);
491 static void remove_session_cb(GObject *object,
497 GDBusConnection *conn = user_data;
502 result = g_dbus_connection_call_finish(conn, res, &error);
505 ERROR("create session error %s", error->message);
509 g_variant_unref(result);
512 int obex_create_session(const char *destination,
513 enum obex_target target,
514 obex_session_state_cb cb,
517 GVariantBuilder *builder;
518 const char *target_s;
520 struct obex_session_result *async_node;
521 GDBusConnection *connection = _obex_get_session_dbus();
528 async_node = g_new0(struct obex_session_result, 1);
529 if (async_node == NULL) {
535 async_node->user_data = data;
536 async_node->conn = connection;
538 target_s = get_obex_target_string(target);
539 target_v = g_variant_new("s", target_s);
540 builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
541 g_variant_builder_add(builder, "{sv}", "Target", target_v);
543 DBG("destination = %s, target_s = %s", destination, target_s);
545 g_dbus_connection_call(connection, "org.bluez.obex",
547 "org.bluez.obex.Client1",
549 g_variant_new("(sa{sv})",
550 destination, builder),
551 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
552 create_session_cb, async_node);
554 g_variant_builder_unref(builder);
561 void obex_session_remove_session(const char *object_path)
563 GDBusConnection *connection = _obex_get_session_dbus();
570 g_dbus_connection_call(connection, "org.bluez.obex",
572 "org.bluez.obex.Client1",
574 g_variant_new("(o)", object_path),
575 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
576 remove_session_cb, connection);
579 struct obex_transfer_result {
580 obex_transfer_state_cb cb;
582 GDBusConnection *conn;
585 static void create_transfer_cb(GObject *object,
589 GError *error = NULL;
592 struct obex_transfer_result *async_node = user_data;
596 result = g_dbus_connection_call_finish(async_node->conn,
599 async_node = user_data;
602 ERROR("transfer error %s", error->message);
604 async_node->cb(NULL, OBEX_TRANSFER_ERROR, NULL, 0, 0,
605 NULL, g_strdup(error->message));
609 g_variant_get(result, "(oa{sv})", &transfer, NULL);
611 DBG("transfer created %s", transfer);
613 async_node->cb(g_strdup(transfer), OBEX_TRANSFER_QUEUED,
614 NULL, 0, 0, async_node->user_data, NULL);
618 g_variant_unref(result);
626 void obex_session_opp_send_file(const char *session,
628 obex_transfer_state_cb cb,
631 struct obex_transfer_result *async_node;
632 GDBusConnection *connection = _obex_get_session_dbus();
639 async_node = g_new0(struct obex_transfer_result, 1);
640 if (async_node == NULL) {
646 async_node->user_data = data;
647 async_node->conn = connection;
649 g_dbus_connection_call(connection, "org.bluez.obex",
651 "org.bluez.obex.ObjectPush1",
653 g_variant_new("(s)", file),
654 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
655 create_transfer_cb, async_node);
658 struct obex_watch_result {
659 obex_transfer_state_cb cb;
662 unsigned int proxy_id;
666 int obex_get_transfer_id(const char *transfer_path, enum obex_role role)
669 char *p = g_strrstr(transfer_path, "transfer");
672 ERROR("Can't get transfer id");
678 if (role == OBEX_SERVER)
681 DBG("transfer id %d", id);
686 static void transfer_properties_changed(GDBusProxy *proxy,
687 GVariant *changed_properties,
688 GStrv *invalidated_properties,
691 struct obex_watch_result *async_node = user_data;
693 enum transfer_state state;
696 gboolean variant_found;
697 guint64 transferred = 0;
700 gchar *properties = g_variant_print(changed_properties, TRUE);
702 DBG("properties %s", properties);
705 if (!async_node || !async_node->path)
708 p_proxy = g_dbus_proxy_new_for_bus_sync(
709 G_BUS_TYPE_SESSION, 0,
713 PROPERTIES_INTERFACE,
719 variant_found = g_variant_lookup(changed_properties,
720 "Status", "s", &status);
723 DBG("status = %s", status);
724 state = get_transfer_state_from_string(status);
725 if (state == OBEX_TRANSFER_ERROR ||
726 state == OBEX_TRANSFER_COMPLETE)
729 status = property_get_string(p_proxy,
730 OBEX_TRANSFER_INTERFACE, "Status");
731 state = get_transfer_state_from_string(status);
734 variant_found = g_variant_lookup(changed_properties,
735 "Transferred", "t", &transferred);
738 property_get_uint64(p_proxy,
739 OBEX_TRANSFER_INTERFACE,
740 "Transferred", &transferred);
741 name = property_get_string(p_proxy,
742 OBEX_TRANSFER_INTERFACE, "Filename");
744 property_get_uint64(p_proxy,
745 OBEX_TRANSFER_INTERFACE, "Size", &size);
747 DBG("state: %d, %ju, %s, %s, %ju", state, transferred,
750 async_node->cb(async_node->path, state, name, size,
751 transferred, async_node->user_data, NULL);
753 g_object_unref(p_proxy);
756 DBG("state: %d, %ju, %s, %s, %ju", state, transferred,
759 async_node->cb(async_node->path, state, name, size, transferred,
760 async_node->user_data, NULL);
762 g_signal_handler_disconnect(async_node->proxy,
763 async_node->proxy_id);
764 g_object_unref(p_proxy);
765 g_object_unref(async_node->proxy);
766 if (async_node->path)
767 g_free(async_node->path);
768 async_node->path = NULL;
773 /* notify specific transfer */
774 int obex_transfer_set_notify(char *transfer_path,
775 obex_transfer_state_cb cb, void *data)
777 struct obex_watch_result *async_node;
782 async_node = g_new0(struct obex_watch_result, 1);
783 if (async_node == NULL) {
788 DBG("transfer_path = %s", transfer_path);
789 proxy = g_dbus_proxy_new_for_bus_sync(
790 G_BUS_TYPE_SESSION, 0,
794 "org.bluez.obex.Transfer1",
799 WARN("properties proxy error");
804 async_node->user_data = data;
805 async_node->proxy = g_object_ref(proxy);
806 async_node->path = g_strdup(transfer_path);
808 async_node->proxy_id = g_signal_connect(async_node->proxy,
809 "g-properties-changed",
810 G_CALLBACK(transfer_properties_changed),
816 static void simple_cancle_cb(GObject *object,
817 GAsyncResult *res, gpointer user_data)
821 GDBusConnection *conn = user_data;
826 result = g_dbus_connection_call_finish(conn, res, &error);
829 ERROR("create session error %s", error->message);
832 g_variant_unref(result);
835 void obex_transfer_cancel(const char *path)
837 GDBusConnection *connection = _obex_get_session_dbus();
847 g_dbus_connection_call(connection, "org.bluez.obex",
849 "org.bluez.obex.Transfer1",
852 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
853 simple_cancle_cb, connection);
856 static char *_obex_transfer_get_property_session(const char *path)
858 char *session = NULL;
863 p_proxy = g_dbus_proxy_new_for_bus_sync(
864 G_BUS_TYPE_SESSION, 0,
868 PROPERTIES_INTERFACE,
872 session = property_get_string(p_proxy,
873 OBEX_TRANSFER_INTERFACE, "Session");
875 g_object_unref(p_proxy);
880 char *obex_transfer_get_property_source(const char *path)
882 char *source = NULL, *session;
887 session = _obex_transfer_get_property_session(path);
889 DBG("session = %s", session);
891 p_proxy = g_dbus_proxy_new_for_bus_sync(
892 G_BUS_TYPE_SESSION, 0,
896 PROPERTIES_INTERFACE,
900 source = property_get_string(p_proxy,
901 OBEX_SESSION_INTERFACE, "Source");
903 g_object_unref(p_proxy);
908 char *obex_transfer_get_property_destination(const char *path)
910 char *dest = NULL, *session;
913 session = _obex_transfer_get_property_session(path);
915 DBG("session = %s, path = %s", session, path);
917 p_proxy = g_dbus_proxy_new_for_bus_sync(
918 G_BUS_TYPE_SESSION, 0,
922 PROPERTIES_INTERFACE,
926 dest = property_get_string(p_proxy,
927 OBEX_SESSION_INTERFACE, "Destination");
929 g_object_unref(p_proxy);
934 char *obex_transfer_get_property_file_name(const char *path)
939 p_proxy = g_dbus_proxy_new_for_bus_sync(
940 G_BUS_TYPE_SESSION, 0,
944 PROPERTIES_INTERFACE,
948 name = property_get_string(p_proxy,
949 OBEX_TRANSFER_INTERFACE, "Filename");
951 g_object_unref(p_proxy);
956 char *obex_transfer_get_property_name(const char *path)
961 DBG("path = %s", path);
963 p_proxy = g_dbus_proxy_new_for_bus_sync(
964 G_BUS_TYPE_SESSION, 0,
968 PROPERTIES_INTERFACE,
972 name = property_get_string(p_proxy,
973 OBEX_TRANSFER_INTERFACE, "Name");
975 g_object_unref(p_proxy);