// SPDX-License-Identifier: GPL-2.0-or-later /* * * OBEX Client * * Copyright (C) 2007-2010 Intel Corporation * Copyright (C) 2007-2010 Marcel Holtmann * * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "gdbus/gdbus.h" #include "obexd/src/log.h" #include "transfer.h" #include "session.h" #include "driver.h" #include "sync.h" #define OBEX_SYNC_UUID "IRMC-SYNC" #define OBEX_SYNC_UUID_LEN 9 #define SYNC_INTERFACE "org.bluez.obex.Synchronization1" #define ERROR_INF SYNC_INTERFACE ".Error" #define SYNC_UUID "00001104-0000-1000-8000-00805f9b34fb" struct sync_data { struct obc_session *session; char *phonebook_path; DBusMessage *msg; }; static DBusConnection *conn = NULL; static DBusMessage *sync_setlocation(DBusConnection *connection, DBusMessage *message, void *user_data) { struct sync_data *sync = user_data; const char *location; char *path = NULL, *tmp; if (dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &location, DBUS_TYPE_INVALID) == FALSE) return g_dbus_create_error(message, ERROR_INF ".InvalidArguments", NULL); if (!g_ascii_strcasecmp(location, "int") || !g_ascii_strcasecmp(location, "internal")) path = g_strdup("telecom/pb.vcf"); else if (!g_ascii_strncasecmp(location, "sim", 3)) { tmp = g_ascii_strup(location, 4); path = g_build_filename(tmp, "telecom/pb.vcf", NULL); g_free(tmp); } else return g_dbus_create_error(message, ERROR_INF ".InvalidArguments", "InvalidPhonebook"); g_free(sync->phonebook_path); sync->phonebook_path = path; return dbus_message_new_method_return(message); } static DBusMessage *sync_getphonebook(DBusConnection *connection, DBusMessage *message, void *user_data) { struct sync_data *sync = user_data; struct obc_transfer *transfer; const char *target_file; GError *err = NULL; DBusMessage *reply; if (dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &target_file, DBUS_TYPE_INVALID) == FALSE) return g_dbus_create_error(message, ERROR_INF ".InvalidArguments", "Invalid arguments in method call"); if (sync->msg) return g_dbus_create_error(message, ERROR_INF ".InProgress", "Transfer in progress"); /* set default phonebook_path to memory internal phonebook */ if (!sync->phonebook_path) sync->phonebook_path = g_strdup("telecom/pb.vcf"); transfer = obc_transfer_get("phonebook", sync->phonebook_path, target_file, &err); if (transfer == NULL) goto fail; if (!obc_session_queue(sync->session, transfer, NULL, NULL, &err)) goto fail; return obc_transfer_create_dbus_reply(transfer, message); fail: reply = g_dbus_create_error(message, ERROR_INF ".Failed", "%s", err->message); g_error_free(err); return reply; } static DBusMessage *sync_putphonebook(DBusConnection *connection, DBusMessage *message, void *user_data) { struct sync_data *sync = user_data; struct obc_transfer *transfer; const char *source_file; GError *err = NULL; DBusMessage *reply; if (dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &source_file, DBUS_TYPE_INVALID) == FALSE) return g_dbus_create_error(message, ERROR_INF ".InvalidArguments", "Invalid arguments in method call"); /* set default phonebook_path to memory internal phonebook */ if (!sync->phonebook_path) sync->phonebook_path = g_strdup("telecom/pb.vcf"); transfer = obc_transfer_put(NULL, sync->phonebook_path, source_file, NULL, 0, &err); if (transfer == NULL) goto fail; if (!obc_session_queue(sync->session, transfer, NULL, NULL, &err)) goto fail; return obc_transfer_create_dbus_reply(transfer, message); fail: reply = g_dbus_create_error(message, ERROR_INF ".Failed", "%s", err->message); g_error_free(err); return reply; } static const GDBusMethodTable sync_methods[] = { { GDBUS_METHOD("SetLocation", GDBUS_ARGS({ "location", "s" }), NULL, sync_setlocation) }, { GDBUS_METHOD("GetPhonebook", GDBUS_ARGS({ "targetfile", "s" }), GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }), sync_getphonebook) }, { GDBUS_METHOD("PutPhonebook", GDBUS_ARGS({ "sourcefile", "s" }), GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }), sync_putphonebook) }, { } }; static void sync_free(void *data) { struct sync_data *sync = data; obc_session_unref(sync->session); g_free(sync->phonebook_path); g_free(sync); } static int sync_probe(struct obc_session *session) { struct sync_data *sync; const char *path; path = obc_session_get_path(session); DBG("%s", path); sync = g_try_new0(struct sync_data, 1); if (!sync) return -ENOMEM; sync->session = obc_session_ref(session); if (!g_dbus_register_interface(conn, path, SYNC_INTERFACE, sync_methods, NULL, NULL, sync, sync_free)) { sync_free(sync); return -ENOMEM; } return 0; } static void sync_remove(struct obc_session *session) { const char *path = obc_session_get_path(session); DBG("%s", path); g_dbus_unregister_interface(conn, path, SYNC_INTERFACE); } static struct obc_driver sync = { .service = "SYNC", .uuid = SYNC_UUID, .target = OBEX_SYNC_UUID, .target_len = OBEX_SYNC_UUID_LEN, .probe = sync_probe, .remove = sync_remove }; int sync_init(void) { int err; DBG(""); conn = dbus_bus_get(DBUS_BUS_SESSION, NULL); if (!conn) return -EIO; err = obc_driver_register(&sync); if (err < 0) { dbus_connection_unref(conn); conn = NULL; return err; } return 0; } void sync_exit(void) { DBG(""); dbus_connection_unref(conn); conn = NULL; obc_driver_unregister(&sync); }