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;
50 static GList *transfer_watched_list;
52 static GDBusConnection *_obex_get_session_dbus(void)
60 g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
61 if (g_connection == NULL) {
62 DBG("%s", error->message);
69 void obex_agent_set_agent_added(obex_agent_added_cb_t cb, void *user_data)
71 obex_agent_added_cb = cb;
72 obex_agent_added_cb_data = user_data;
75 void obex_agent_unset_agent_added(void)
77 obex_agent_added_cb = NULL;
78 obex_agent_added_cb_data = NULL;
84 GDBusConnection *conn;
87 static void agent_callback(GObject *source_object,
93 enum bluez_error_type error_type = ERROR_NONE;
94 struct agent_data *agent_data = user_data;
98 ret = g_dbus_connection_call_finish(agent_data->conn,
101 error_type = get_error_type(error);
102 ERROR("error = %d", error_type);
106 agent_data->cb(error_type, agent_data->user_data);
113 void obex_agent_register_agent(const char *agent_path,
117 struct agent_data *register_data;
118 GDBusConnection *connection = _obex_get_session_dbus();
122 register_data = g_new0(struct agent_data, 1);
123 if (register_data == NULL) {
128 register_data->cb = cb;
129 register_data->user_data = user_data;
130 register_data->conn = connection;
133 g_dbus_connection_call(connection, "org.bluez.obex",
135 "org.bluez.obex.AgentManager1",
137 g_variant_new("(o)", agent_path),
138 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
139 agent_callback, register_data);
141 ERROR("agent not registered");
144 void obex_agent_unregister_agent(const char *agent_path,
148 struct agent_data *unregister_data;
149 GDBusConnection *connection = _obex_get_session_dbus();
153 unregister_data = g_new0(struct agent_data, 1);
154 if (unregister_data == NULL) {
159 unregister_data->cb = cb;
160 unregister_data->user_data = user_data;
163 g_dbus_connection_call(connection, "org.bluez.obex",
165 "org.bluez.obex.AgentManager1",
167 g_variant_new("(o)", agent_path),
168 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
169 agent_callback, unregister_data);
171 ERROR("agent not registered");
174 static enum transfer_state get_transfer_state_from_string(const char *string)
177 return OBEX_TRANSFER_UNKNOWN;
179 if (!g_strcmp0(string, "queued"))
180 return OBEX_TRANSFER_QUEUED;
182 if (!g_strcmp0(string, "active"))
183 return OBEX_TRANSFER_ACTIVE;
185 if (!g_strcmp0(string, "complete"))
186 return OBEX_TRANSFER_COMPLETE;
188 if (!g_strcmp0(string, "error"))
189 return OBEX_TRANSFER_ERROR;
191 return OBEX_TRANSFER_UNKNOWN;
194 enum transfer_state obex_transfer_get_property_state(const char *path)
201 p_proxy = g_dbus_proxy_new_for_bus_sync(
202 G_BUS_TYPE_SESSION, 0,
206 PROPERTIES_INTERFACE,
210 status = property_get_string(p_proxy,
211 OBEX_TRANSFER_INTERFACE, "Status");
213 g_object_unref(p_proxy);
215 return get_transfer_state_from_string(status);
218 int obex_transfer_get_property_transferred(const char *path,
226 p_proxy = g_dbus_proxy_new_for_bus_sync(
227 G_BUS_TYPE_SESSION, 0,
231 PROPERTIES_INTERFACE,
235 ret = property_get_uint64(p_proxy,
236 OBEX_TRANSFER_INTERFACE, "Transferred", u64);
238 g_object_unref(p_proxy);
243 int obex_transfer_get_property_size(const char *path,
249 DBG("path = %s", path);
250 p_proxy = g_dbus_proxy_new_for_bus_sync(
251 G_BUS_TYPE_SESSION, 0,
255 PROPERTIES_INTERFACE,
259 ret = property_get_uint64(p_proxy,
260 OBEX_TRANSFER_INTERFACE, "Size", u64);
262 g_object_unref(p_proxy);
267 static void parse_object(gpointer data, gpointer user_data)
269 GDBusObject *obj = data;
270 const char *path = g_dbus_object_get_object_path(obj);
273 DBG("object path name %s", path);
275 if (!g_strcmp0(path, OBJECT_OBEX_PATH)) {
276 if (g_opp_startup == 1)
279 if (obex_agent_added_cb)
280 obex_agent_added_cb(obex_agent_added_cb_data);
287 static void interfaces_removed(GVariant *parameters)
292 gchar *parameters_s = g_variant_print(parameters, TRUE);
294 g_variant_get(parameters, "(oas)", &object_path, &iter);
296 DBG("%s", parameters_s);
298 g_free(parameters_s);
300 DBG("%s", object_path);
302 if (!g_strcmp0(object_path, OBJECT_OBEX_PATH))
306 static void interfaces_added(GVariant *parameters)
311 g_variant_get(parameters, "(oa{sa{sv}})", &object_path, NULL);
313 DBG("object %s", object_path);
315 obj = g_dbus_object_manager_get_object(object_manager, object_path);
318 parse_object(obj, NULL);
321 static gboolean handle_interfaces_added(gpointer user_data)
323 GVariant *parameters = user_data;
325 interfaces_added(parameters);
327 g_variant_unref(parameters);
332 static void interfaces_changed(GDBusProxy *proxy,
335 GVariant *parameters,
338 if (!g_strcmp0(signal_name, "InterfacesAdded"))
339 g_idle_add(handle_interfaces_added,
340 g_variant_ref_sink(parameters));
341 if (!g_strcmp0(signal_name, "InterfacesRemoved"))
342 interfaces_removed(parameters);
345 int obex_agent_get_agent(void)
347 return g_opp_startup;
350 int obex_lib_init(void)
356 if (object_manager != NULL)
359 manager_proxy = g_dbus_proxy_new_for_bus_sync(
360 G_BUS_TYPE_SESSION, 0,
367 if (manager_proxy == NULL)
368 ERROR("create manager_proxy error");
370 DBG("manager proxy 0x%p created", manager_proxy);
372 g_signal_connect(manager_proxy,
374 G_CALLBACK(interfaces_changed),
378 object_manager = g_dbus_object_manager_client_new_for_bus_sync(
386 if (object_manager == NULL) {
387 ERROR("create object manager error");
388 /* TODO: define error type */
392 DBG("object manager %p is created", object_manager);
394 obj_list = g_dbus_object_manager_get_objects(object_manager);
396 g_list_foreach(obj_list, parse_object, NULL);
401 static void destruct_obex_object_manager(void)
405 g_object_unref(object_manager);
407 object_manager = NULL;
410 void obex_lib_deinit(void)
415 g_object_unref(manager_proxy);
417 destruct_obex_object_manager();
420 struct obex_session_result {
421 obex_session_state_cb cb;
423 GDBusConnection *conn;
426 static const char *get_obex_target_string(enum obex_target target)
429 case OBEX_TARGET_UNKNOWN:
448 static void create_session_cb(GObject *object,
455 struct obex_session_result *async_node;
458 async_node = user_data;
462 result = g_dbus_connection_call_finish(async_node->conn,
466 ERROR("create session error %s", error->message);
468 async_node->cb(NULL, NULL, OBEX_SESSION_FAILED,
469 async_node->user_data,
470 g_strdup(error->message));
475 g_variant_get(result, "(o)", &session);
477 DBG("Sesseion created %s", session);
479 async_node->cb(NULL, session, OBEX_SESSION_CREATED,
480 async_node->user_data, NULL);
484 g_variant_unref(result);
492 static void remove_session_cb(GObject *object,
498 GDBusConnection *conn = user_data;
503 result = g_dbus_connection_call_finish(conn, res, &error);
506 ERROR("create session error %s", error->message);
510 g_variant_unref(result);
513 int obex_create_session(const char *destination,
514 enum obex_target target,
515 obex_session_state_cb cb,
518 GVariantBuilder *builder;
519 const char *target_s;
521 struct obex_session_result *async_node;
522 GDBusConnection *connection = _obex_get_session_dbus();
529 async_node = g_new0(struct obex_session_result, 1);
530 if (async_node == NULL) {
536 async_node->user_data = data;
537 async_node->conn = connection;
539 target_s = get_obex_target_string(target);
540 target_v = g_variant_new("s", target_s);
541 builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
542 g_variant_builder_add(builder, "{sv}", "Target", target_v);
544 DBG("destination = %s, target_s = %s", destination, target_s);
546 g_dbus_connection_call(connection, "org.bluez.obex",
548 "org.bluez.obex.Client1",
550 g_variant_new("(sa{sv})",
551 destination, builder),
552 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
553 create_session_cb, async_node);
555 g_variant_builder_unref(builder);
562 void obex_session_remove_session(const char *object_path)
564 GDBusConnection *connection = _obex_get_session_dbus();
571 g_dbus_connection_call(connection, "org.bluez.obex",
573 "org.bluez.obex.Client1",
575 g_variant_new("(o)", object_path),
576 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
577 remove_session_cb, connection);
580 struct obex_transfer_result {
581 obex_transfer_state_cb cb;
583 GDBusConnection *conn;
586 static void create_transfer_cb(GObject *object,
590 GError *error = NULL;
593 struct obex_transfer_result *async_node = user_data;
597 result = g_dbus_connection_call_finish(async_node->conn,
600 async_node = user_data;
603 ERROR("transfer error %s", error->message);
605 async_node->cb(NULL, OBEX_TRANSFER_ERROR, NULL, 0, 0,
606 NULL, g_strdup(error->message));
610 g_variant_get(result, "(oa{sv})", &transfer, NULL);
612 DBG("transfer created %s", transfer);
614 async_node->cb(g_strdup(transfer), OBEX_TRANSFER_QUEUED,
615 NULL, 0, 0, async_node->user_data, NULL);
619 g_variant_unref(result);
627 void obex_session_opp_send_file(const char *session,
629 obex_transfer_state_cb cb,
632 struct obex_transfer_result *async_node;
633 GDBusConnection *connection = _obex_get_session_dbus();
640 async_node = g_new0(struct obex_transfer_result, 1);
641 if (async_node == NULL) {
647 async_node->user_data = data;
648 async_node->conn = connection;
650 g_dbus_connection_call(connection, "org.bluez.obex",
652 "org.bluez.obex.ObjectPush1",
654 g_variant_new("(s)", file),
655 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
656 create_transfer_cb, async_node);
659 struct obex_watch_result {
660 obex_transfer_state_cb cb;
663 unsigned int proxy_id;
667 int obex_get_transfer_id(const char *transfer_path, enum obex_role role)
670 char *p = g_strrstr(transfer_path, "transfer");
673 ERROR("Can't get transfer id");
679 if (role == OBEX_SERVER)
682 DBG("transfer id %d", id);
687 static struct obex_watch_result *find_watch_node(const char *path)
689 struct obex_watch_result *node;
692 DBG("path = %s", path);
694 if (!transfer_watched_list ||
695 !g_list_length(transfer_watched_list))
698 for (list = g_list_first(transfer_watched_list);
700 next = g_list_next(list);
703 if (node && !g_strcmp0(node->path, path))
710 static void transfer_properties_changed(GDBusProxy *proxy,
711 GVariant *changed_properties,
712 GStrv *invalidated_properties,
715 struct obex_watch_result *async_node = user_data;
717 enum transfer_state state;
720 gboolean variant_found;
721 guint64 transferred = 0;
724 gchar *properties = g_variant_print(changed_properties, TRUE);
726 DBG("properties %s", properties);
729 if (!async_node || !async_node->path)
732 p_proxy = g_dbus_proxy_new_for_bus_sync(
733 G_BUS_TYPE_SESSION, 0,
737 PROPERTIES_INTERFACE,
743 variant_found = g_variant_lookup(changed_properties,
744 "Status", "s", &status);
747 DBG("status = %s", status);
748 state = get_transfer_state_from_string(status);
749 if (state == OBEX_TRANSFER_ERROR ||
750 state == OBEX_TRANSFER_COMPLETE)
753 status = property_get_string(p_proxy,
754 OBEX_TRANSFER_INTERFACE, "Status");
755 state = get_transfer_state_from_string(status);
758 variant_found = g_variant_lookup(changed_properties,
759 "Transferred", "t", &transferred);
762 property_get_uint64(p_proxy,
763 OBEX_TRANSFER_INTERFACE,
764 "Transferred", &transferred);
765 name = property_get_string(p_proxy,
766 OBEX_TRANSFER_INTERFACE, "Filename");
768 property_get_uint64(p_proxy,
769 OBEX_TRANSFER_INTERFACE, "Size", &size);
771 DBG("state: %d, %ju, %s, %s, %ju", state, transferred,
774 async_node->cb(async_node->path, state, name, size,
775 transferred, async_node->user_data, NULL);
777 g_object_unref(p_proxy);
780 DBG("state: %d, %ju, %s, %s, %ju", state, transferred,
783 async_node->cb(async_node->path, state, name, size, transferred,
784 async_node->user_data, NULL);
786 g_signal_handler_disconnect(async_node->proxy,
787 async_node->proxy_id);
789 transfer_watched_list = g_list_remove(transfer_watched_list,
791 g_object_unref(p_proxy);
792 g_object_unref(async_node->proxy);
793 if (async_node->path)
794 g_free(async_node->path);
795 async_node->path = NULL;
800 /* notify specific transfer */
801 int obex_transfer_set_notify(char *transfer_path,
802 obex_transfer_state_cb cb, void *data)
804 struct obex_watch_result *async_node;
809 async_node = g_new0(struct obex_watch_result, 1);
810 if (async_node == NULL) {
815 DBG("transfer_path = %s", transfer_path);
816 proxy = g_dbus_proxy_new_for_bus_sync(
817 G_BUS_TYPE_SESSION, 0,
821 "org.bluez.obex.Transfer1",
826 WARN("properties proxy error");
831 async_node->user_data = data;
832 async_node->proxy = g_object_ref(proxy);
833 async_node->path = g_strdup(transfer_path);
835 async_node->proxy_id = g_signal_connect(async_node->proxy,
836 "g-properties-changed",
837 G_CALLBACK(transfer_properties_changed),
840 transfer_watched_list = g_list_append(transfer_watched_list,
846 void obex_transfer_clear_notify(char *transfer_path)
848 struct obex_watch_result *async_node;
850 DBG("transfer_path = %s", transfer_path);
855 async_node = find_watch_node(transfer_path);
859 g_signal_handler_disconnect(async_node->proxy,
860 async_node->proxy_id);
862 transfer_watched_list = g_list_remove(transfer_watched_list,
865 g_object_unref(async_node->proxy);
866 if (async_node->path)
867 g_free(async_node->path);
871 static void simple_cancle_cb(GObject *object,
872 GAsyncResult *res, gpointer user_data)
876 GDBusConnection *conn = user_data;
881 result = g_dbus_connection_call_finish(conn, res, &error);
884 ERROR("create session error %s", error->message);
887 g_variant_unref(result);
890 void obex_transfer_cancel(const char *path)
892 GDBusConnection *connection = _obex_get_session_dbus();
902 DBG("path = %s", path);
904 g_dbus_connection_call(connection, "org.bluez.obex",
906 "org.bluez.obex.Transfer1",
909 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
910 simple_cancle_cb, connection);
913 static char *_obex_transfer_get_property_session(const char *path)
915 char *session = NULL;
920 p_proxy = g_dbus_proxy_new_for_bus_sync(
921 G_BUS_TYPE_SESSION, 0,
925 PROPERTIES_INTERFACE,
929 session = property_get_string(p_proxy,
930 OBEX_TRANSFER_INTERFACE, "Session");
932 g_object_unref(p_proxy);
937 char *obex_transfer_get_property_source(const char *path)
939 char *source = NULL, *session;
944 session = _obex_transfer_get_property_session(path);
946 DBG("session = %s", session);
948 p_proxy = g_dbus_proxy_new_for_bus_sync(
949 G_BUS_TYPE_SESSION, 0,
953 PROPERTIES_INTERFACE,
957 source = property_get_string(p_proxy,
958 OBEX_SESSION_INTERFACE, "Source");
960 g_object_unref(p_proxy);
965 char *obex_transfer_get_property_destination(const char *path)
967 char *dest = NULL, *session;
970 session = _obex_transfer_get_property_session(path);
972 DBG("session = %s, path = %s", session, path);
974 p_proxy = g_dbus_proxy_new_for_bus_sync(
975 G_BUS_TYPE_SESSION, 0,
979 PROPERTIES_INTERFACE,
983 dest = property_get_string(p_proxy,
984 OBEX_SESSION_INTERFACE, "Destination");
986 g_object_unref(p_proxy);
991 char *obex_transfer_get_property_file_name(const char *path)
996 p_proxy = g_dbus_proxy_new_for_bus_sync(
997 G_BUS_TYPE_SESSION, 0,
1001 PROPERTIES_INTERFACE,
1005 name = property_get_string(p_proxy,
1006 OBEX_TRANSFER_INTERFACE, "Filename");
1008 g_object_unref(p_proxy);
1013 char *obex_transfer_get_property_name(const char *path)
1016 GDBusProxy *p_proxy;
1018 DBG("path = %s", path);
1020 p_proxy = g_dbus_proxy_new_for_bus_sync(
1021 G_BUS_TYPE_SESSION, 0,
1025 PROPERTIES_INTERFACE,
1029 name = property_get_string(p_proxy,
1030 OBEX_TRANSFER_INTERFACE, "Name");
1032 g_object_unref(p_proxy);