@@ -82,6 +82,7 @@ obexd_src_obexd_SOURCES = $(btio_sources) $(gobex_sources) \
obexd/client/ftp.h obexd/client/ftp.c \
obexd/client/opp.h obexd/client/opp.c \
obexd/client/map.h obexd/client/map.c \
+ obexd/client/bip-avrcp.h obexd/client/bip-avrcp.c \
obexd/client/map-event.h obexd/client/map-event.c \
obexd/client/transfer.h obexd/client/transfer.c \
obexd/client/transport.h obexd/client/transport.c \
new file mode 100644
@@ -0,0 +1,171 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ * OBEX Client
+ *
+ * Copyright (C) 2024 Collabora Ltd.
+ *
+ *
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gdbus/gdbus.h"
+#include "gobex/gobex.h"
+
+#include "obexd/src/log.h"
+#include "transfer.h"
+#include "session.h"
+#include "driver.h"
+#include "bip-avrcp.h"
+
+#define OBEX_BIP_AVRCP_UUID \
+ "\x71\x63\xDD\x54\x4A\x7E\x11\xE2\xB4\x7C\x00\x50\xC2\x49\x00\x48"
+#define OBEX_BIP_AVRCP_UUID_LEN 16
+
+#define BIP_AVRCP_INTERFACE "org.bluez.obex.BipAvrcp1"
+#define ERROR_INTERFACE "org.bluez.obex.Error"
+#define BIP_AVRCP_UUID "0000111A-0000-1000-8000-00805f9b34fb"
+
+#define IMG_HANDLE_TAG 0x30
+
+static DBusConnection *conn;
+
+struct bip_avrcp_data {
+ struct obc_session *session;
+};
+
+static DBusMessage *get_image_thumbnail(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ struct bip_avrcp_data *bip_avrcp = user_data;
+ const char *handle = NULL, *image_path = NULL;
+ struct obc_transfer *transfer;
+ GObexHeader *header;
+ DBusMessage *reply = NULL;
+ GError *err = NULL;
+
+ DBG("");
+
+ if (dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &image_path,
+ DBUS_TYPE_STRING, &handle,
+ DBUS_TYPE_INVALID) == FALSE) {
+ reply = g_dbus_create_error(message,
+ ERROR_INTERFACE ".InvalidArguments", NULL);
+ goto fail;
+ }
+
+ transfer = obc_transfer_get("x-bt/img-thm", NULL, image_path, &err);
+ if (transfer == NULL)
+ goto fail;
+
+ header = g_obex_header_new_unicode(IMG_HANDLE_TAG, handle);
+ obc_transfer_add_header(transfer, header);
+
+ if (!obc_session_queue(bip_avrcp->session, transfer, NULL, NULL, &err))
+ goto fail;
+
+ return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+ reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+ err->message);
+ g_error_free(err);
+ return reply;
+}
+
+static const GDBusMethodTable bip_avrcp_methods[] = {
+ { GDBUS_ASYNC_METHOD("GetImageThumbnail",
+ GDBUS_ARGS({ "file", "s" }, { "handle", "s"}),
+ GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
+ get_image_thumbnail) },
+ { }
+};
+
+static void bip_avrcp_free(void *data)
+{
+ struct bip_avrcp_data *bip_avrcp = data;
+
+ obc_session_unref(bip_avrcp->session);
+ g_free(bip_avrcp);
+}
+
+static int bip_avrcp_probe(struct obc_session *session)
+{
+ struct bip_avrcp_data *bip_avrcp;
+ const char *path;
+
+ path = obc_session_get_path(session);
+
+ DBG("%s", path);
+
+ bip_avrcp = g_try_new0(struct bip_avrcp_data, 1);
+ if (!bip_avrcp)
+ return -ENOMEM;
+
+ bip_avrcp->session = obc_session_ref(session);
+
+ if (!g_dbus_register_interface(conn, path, BIP_AVRCP_INTERFACE,
+ bip_avrcp_methods,
+ NULL, NULL,
+ bip_avrcp, bip_avrcp_free)) {
+ bip_avrcp_free(bip_avrcp);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void bip_avrcp_remove(struct obc_session *session)
+{
+ const char *path = obc_session_get_path(session);
+
+ DBG("%s", path);
+
+ g_dbus_unregister_interface(conn, path, BIP_AVRCP_INTERFACE);
+}
+
+static struct obc_driver bip_avrcp = {
+ .service = "BIP-AVRCP",
+ .uuid = BIP_AVRCP_UUID,
+ .target = OBEX_BIP_AVRCP_UUID,
+ .target_len = OBEX_BIP_AVRCP_UUID_LEN,
+ .probe = bip_avrcp_probe,
+ .remove = bip_avrcp_remove
+};
+
+int bip_avrcp_init(void)
+{
+ int err;
+
+ DBG("");
+
+ conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+ if (!conn)
+ return -EIO;
+
+ err = obc_driver_register(&bip_avrcp);
+ if (err < 0)
+ goto failed;
+
+ return 0;
+
+failed:
+ dbus_connection_unref(conn);
+ conn = NULL;
+ return err;
+}
+
+void bip_avrcp_exit(void)
+{
+ DBG("");
+
+ dbus_connection_unref(conn);
+ conn = NULL;
+
+ obc_driver_unregister(&bip_avrcp);
+}
new file mode 100644
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ * OBEX Client
+ *
+ * Copyright (C) 2024 Collabora Ltd.
+ *
+ *
+ */
+
+int bip_avrcp_init(void);
+void bip_avrcp_exit(void);
@@ -32,6 +32,7 @@
#include "pbap.h"
#include "sync.h"
#include "map.h"
+#include "bip-avrcp.h"
#include "manager.h"
#define CLIENT_INTERFACE "org.bluez.obex.Client1"
@@ -258,6 +259,7 @@ static const struct obc_module {
{ "pbap", pbap_init, pbap_exit },
{ "sync", sync_init, sync_exit },
{ "map", map_init, map_exit },
+ { "bip-avrcp", bip_avrcp_init, bip_avrcp_exit },
{ }
};
@@ -57,6 +57,7 @@ struct obc_transfer {
GObex *obex;
uint8_t status;
GObexApparam *apparam;
+ GSList *headers;
guint8 op;
struct transfer_callback *callback;
DBusConnection *conn;
@@ -820,6 +821,16 @@ static gboolean transfer_start_get(struct obc_transfer *transfer, GError **err)
g_obex_packet_add_bytes(req, G_OBEX_HDR_TYPE, transfer->type,
strlen(transfer->type) + 1);
+ if (transfer->headers != NULL) {
+ GSList *l;
+
+ for (l = transfer->headers; l != NULL; l = g_slist_next(l)) {
+ GObexHeader *hdr = l->data;
+
+ g_obex_packet_add_header(req, hdr);
+ }
+ }
+
if (transfer->apparam != NULL) {
hdr = g_obex_header_new_apparam(transfer->apparam);
g_obex_packet_add_header(req, hdr);
@@ -974,3 +985,8 @@ gint64 obc_transfer_get_size(struct obc_transfer *transfer)
{
return transfer->size;
}
+
+void obc_transfer_add_header(struct obc_transfer *transfer, void *data)
+{
+ transfer->headers = g_slist_append(transfer->headers, data);
+}
@@ -47,3 +47,5 @@ gint64 obc_transfer_get_size(struct obc_transfer *transfer);
DBusMessage *obc_transfer_create_dbus_reply(struct obc_transfer *transfer,
DBusMessage *message);
+
+void obc_transfer_add_header(struct obc_transfer *transfer, void *data);