Blame obexd/src/manager.c

Packit 34410b
/*
Packit 34410b
 *
Packit 34410b
 *  OBEX Server
Packit 34410b
 *
Packit 34410b
 *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
Packit 34410b
 *
Packit 34410b
 *
Packit 34410b
 *  This program is free software; you can redistribute it and/or modify
Packit 34410b
 *  it under the terms of the GNU General Public License as published by
Packit 34410b
 *  the Free Software Foundation; either version 2 of the License, or
Packit 34410b
 *  (at your option) any later version.
Packit 34410b
 *
Packit 34410b
 *  This program is distributed in the hope that it will be useful,
Packit 34410b
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 34410b
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 34410b
 *  GNU General Public License for more details.
Packit 34410b
 *
Packit 34410b
 *  You should have received a copy of the GNU General Public License
Packit 34410b
 *  along with this program; if not, write to the Free Software
Packit 34410b
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Packit 34410b
 *
Packit 34410b
 */
Packit 34410b
Packit 34410b
#ifdef HAVE_CONFIG_H
Packit 34410b
#include <config.h>
Packit 34410b
#endif
Packit 34410b
Packit 34410b
#include <stdio.h>
Packit 34410b
#include <unistd.h>
Packit 34410b
#include <string.h>
Packit 34410b
#include <errno.h>
Packit 34410b
#include <sys/socket.h>
Packit 34410b
#include <inttypes.h>
Packit 34410b
Packit 34410b
#include "gdbus/gdbus.h"
Packit 34410b
#include "gobex/gobex.h"
Packit 34410b
Packit 34410b
#include "btio/btio.h"
Packit 34410b
#include "obexd.h"
Packit 34410b
#include "obex.h"
Packit 34410b
#include "obex-priv.h"
Packit 34410b
#include "server.h"
Packit 34410b
#include "manager.h"
Packit 34410b
#include "log.h"
Packit 34410b
#include "service.h"
Packit 34410b
Packit 34410b
#define OBEX_BASE_PATH "/org/bluez/obex"
Packit 34410b
#define SESSION_BASE_PATH OBEX_BASE_PATH "/server"
Packit 34410b
#define OBEX_MANAGER_INTERFACE OBEXD_SERVICE ".AgentManager1"
Packit 34410b
#define ERROR_INTERFACE OBEXD_SERVICE ".Error"
Packit 34410b
#define TRANSFER_INTERFACE OBEXD_SERVICE ".Transfer1"
Packit 34410b
#define SESSION_INTERFACE OBEXD_SERVICE ".Session1"
Packit 34410b
#define AGENT_INTERFACE OBEXD_SERVICE ".Agent1"
Packit 34410b
Packit 34410b
#define TIMEOUT 60*1000 /* Timeout for user response (miliseconds) */
Packit 34410b
Packit 34410b
struct agent {
Packit 34410b
	char *bus_name;
Packit 34410b
	char *path;
Packit 34410b
	gboolean auth_pending;
Packit 34410b
	char *new_name;
Packit 34410b
	char *new_folder;
Packit 34410b
	unsigned int watch_id;
Packit 34410b
};
Packit 34410b
Packit 34410b
enum {
Packit 34410b
	TRANSFER_STATUS_QUEUED = 0,
Packit 34410b
	TRANSFER_STATUS_ACTIVE,
Packit 34410b
	TRANSFER_STATUS_COMPLETE,
Packit 34410b
	TRANSFER_STATUS_ERROR
Packit 34410b
};
Packit 34410b
Packit 34410b
struct obex_transfer {
Packit 34410b
	uint8_t status;
Packit 34410b
	char *path;
Packit 34410b
	struct obex_session *session;
Packit 34410b
};
Packit 34410b
Packit 34410b
static struct agent *agent = NULL;
Packit 34410b
Packit 34410b
static DBusConnection *connection = NULL;
Packit 34410b
Packit 34410b
static void agent_free(struct agent *agent)
Packit 34410b
{
Packit 34410b
	if (!agent)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	g_free(agent->new_folder);
Packit 34410b
	g_free(agent->new_name);
Packit 34410b
	g_free(agent->bus_name);
Packit 34410b
	g_free(agent->path);
Packit 34410b
	g_free(agent);
Packit 34410b
}
Packit 34410b
Packit 34410b
static inline DBusMessage *invalid_args(DBusMessage *msg)
Packit 34410b
{
Packit 34410b
	return g_dbus_create_error(msg,
Packit 34410b
			ERROR_INTERFACE ".InvalidArguments",
Packit 34410b
			"Invalid arguments in method call");
Packit 34410b
}
Packit 34410b
Packit 34410b
static inline DBusMessage *not_supported(DBusMessage *msg)
Packit 34410b
{
Packit 34410b
	return g_dbus_create_error(msg,
Packit 34410b
			ERROR_INTERFACE ".NotSupported",
Packit 34410b
			"Operation is not supported");
Packit 34410b
}
Packit 34410b
Packit 34410b
static inline DBusMessage *agent_already_exists(DBusMessage *msg)
Packit 34410b
{
Packit 34410b
	return g_dbus_create_error(msg,
Packit 34410b
			ERROR_INTERFACE ".AlreadyExists",
Packit 34410b
			"Agent already exists");
Packit 34410b
}
Packit 34410b
Packit 34410b
static inline DBusMessage *agent_does_not_exist(DBusMessage *msg)
Packit 34410b
{
Packit 34410b
	return g_dbus_create_error(msg,
Packit 34410b
			ERROR_INTERFACE ".DoesNotExist",
Packit 34410b
			"Agent does not exist");
Packit 34410b
}
Packit 34410b
Packit 34410b
static inline DBusMessage *not_authorized(DBusMessage *msg)
Packit 34410b
{
Packit 34410b
	return g_dbus_create_error(msg,
Packit 34410b
			ERROR_INTERFACE ".NotAuthorized",
Packit 34410b
			"Not authorized");
Packit 34410b
}
Packit 34410b
Packit 34410b
static void agent_disconnected(DBusConnection *conn, void *user_data)
Packit 34410b
{
Packit 34410b
	DBG("Agent exited");
Packit 34410b
	agent_free(agent);
Packit 34410b
	agent = NULL;
Packit 34410b
}
Packit 34410b
Packit 34410b
static DBusMessage *register_agent(DBusConnection *conn,
Packit 34410b
					DBusMessage *msg, void *data)
Packit 34410b
{
Packit 34410b
	const char *path, *sender;
Packit 34410b
Packit 34410b
	if (agent)
Packit 34410b
		return agent_already_exists(msg);
Packit 34410b
Packit 34410b
	if (!dbus_message_get_args(msg, NULL,
Packit 34410b
				DBUS_TYPE_OBJECT_PATH, &path,
Packit 34410b
				DBUS_TYPE_INVALID))
Packit 34410b
		return invalid_args(msg);
Packit 34410b
Packit 34410b
	sender = dbus_message_get_sender(msg);
Packit 34410b
	agent = g_new0(struct agent, 1);
Packit 34410b
	agent->bus_name = g_strdup(sender);
Packit 34410b
	agent->path = g_strdup(path);
Packit 34410b
Packit 34410b
	agent->watch_id = g_dbus_add_disconnect_watch(conn, sender,
Packit 34410b
					agent_disconnected, NULL, NULL);
Packit 34410b
Packit 34410b
	DBG("Agent registered");
Packit 34410b
Packit 34410b
	return dbus_message_new_method_return(msg);
Packit 34410b
}
Packit 34410b
Packit 34410b
static DBusMessage *unregister_agent(DBusConnection *conn,
Packit 34410b
					DBusMessage *msg, void *data)
Packit 34410b
{
Packit 34410b
	const char *path, *sender;
Packit 34410b
Packit 34410b
	if (!agent)
Packit 34410b
		return agent_does_not_exist(msg);
Packit 34410b
Packit 34410b
	if (!dbus_message_get_args(msg, NULL,
Packit 34410b
				DBUS_TYPE_OBJECT_PATH, &path,
Packit 34410b
				DBUS_TYPE_INVALID))
Packit 34410b
		return invalid_args(msg);
Packit 34410b
Packit 34410b
	if (strcmp(agent->path, path) != 0)
Packit 34410b
		return agent_does_not_exist(msg);
Packit 34410b
Packit 34410b
	sender = dbus_message_get_sender(msg);
Packit 34410b
	if (strcmp(agent->bus_name, sender) != 0)
Packit 34410b
		return not_authorized(msg);
Packit 34410b
Packit 34410b
	g_dbus_remove_watch(conn, agent->watch_id);
Packit 34410b
Packit 34410b
	agent_free(agent);
Packit 34410b
	agent = NULL;
Packit 34410b
Packit 34410b
	DBG("Agent unregistered");
Packit 34410b
Packit 34410b
	return dbus_message_new_method_return(msg);
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean get_source(const GDBusPropertyTable *property,
Packit 34410b
					DBusMessageIter *iter, void *data)
Packit 34410b
{
Packit 34410b
	struct obex_session *os = data;
Packit 34410b
	char *s;
Packit 34410b
Packit 34410b
	s = os->src;
Packit 34410b
	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &s);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean get_destination(const GDBusPropertyTable *property,
Packit 34410b
					DBusMessageIter *iter, void *data)
Packit 34410b
{
Packit 34410b
	struct obex_session *os = data;
Packit 34410b
	char *s;
Packit 34410b
Packit 34410b
	s = os->dst;
Packit 34410b
	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &s);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean session_target_exists(const GDBusPropertyTable *property,
Packit 34410b
								void *data)
Packit 34410b
{
Packit 34410b
	struct obex_session *os = data;
Packit 34410b
Packit 34410b
	return os->service->target ? TRUE : FALSE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static char *target2str(const uint8_t *t)
Packit 34410b
{
Packit 34410b
	if (!t)
Packit 34410b
		return NULL;
Packit 34410b
Packit 34410b
	return g_strdup_printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-"
Packit 34410b
				"%02X%02X-%02X%02X%02X%02X%02X%02X",
Packit 34410b
				t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7],
Packit 34410b
				t[8], t[9], t[10], t[11], t[12], t[13], t[14],
Packit 34410b
				t[15]);
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean get_target(const GDBusPropertyTable *property,
Packit 34410b
					DBusMessageIter *iter, void *data)
Packit 34410b
{
Packit 34410b
	struct obex_session *os = data;
Packit 34410b
	char *uuid;
Packit 34410b
Packit 34410b
	uuid = target2str(os->service->target);
Packit 34410b
	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
Packit 34410b
	g_free(uuid);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean get_root(const GDBusPropertyTable *property,
Packit 34410b
					DBusMessageIter *iter, void *data)
Packit 34410b
{
Packit 34410b
	const char *root;
Packit 34410b
Packit 34410b
	root = obex_option_root_folder();
Packit 34410b
	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &root);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static DBusMessage *transfer_cancel(DBusConnection *connection,
Packit 34410b
				DBusMessage *msg, void *user_data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = user_data;
Packit 34410b
	struct obex_session *os = transfer->session;
Packit 34410b
	const char *sender;
Packit 34410b
Packit 34410b
	if (!agent)
Packit 34410b
		return agent_does_not_exist(msg);
Packit 34410b
Packit 34410b
	if (!os)
Packit 34410b
		return invalid_args(msg);
Packit 34410b
Packit 34410b
	sender = dbus_message_get_sender(msg);
Packit 34410b
	if (strcmp(agent->bus_name, sender) != 0)
Packit 34410b
		return not_authorized(msg);
Packit 34410b
Packit 34410b
	os->aborted = TRUE;
Packit 34410b
Packit 34410b
	return dbus_message_new_method_return(msg);
Packit 34410b
}
Packit 34410b
Packit 34410b
static const char *status2str(uint8_t status)
Packit 34410b
{
Packit 34410b
	switch (status) {
Packit 34410b
	case TRANSFER_STATUS_QUEUED:
Packit 34410b
		return "queued";
Packit 34410b
	case TRANSFER_STATUS_ACTIVE:
Packit 34410b
		return "active";
Packit 34410b
	case TRANSFER_STATUS_COMPLETE:
Packit 34410b
		return "complete";
Packit 34410b
	case TRANSFER_STATUS_ERROR:
Packit 34410b
	default:
Packit 34410b
		return "error";
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean transfer_get_status(const GDBusPropertyTable *property,
Packit 34410b
					DBusMessageIter *iter, void *data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = data;
Packit 34410b
	const char *status = status2str(transfer->status);
Packit 34410b
Packit 34410b
	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean transfer_get_session(const GDBusPropertyTable *property,
Packit 34410b
					DBusMessageIter *iter, void *data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = data;
Packit 34410b
	struct obex_session *session = transfer->session;
Packit 34410b
	char *path;
Packit 34410b
Packit 34410b
	if (session == NULL)
Packit 34410b
		return FALSE;
Packit 34410b
Packit 34410b
	path = g_strdup_printf("%s/session%u", SESSION_BASE_PATH, session->id);
Packit 34410b
Packit 34410b
	dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
Packit 34410b
Packit 34410b
	g_free(path);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean transfer_name_exists(const GDBusPropertyTable *property,
Packit 34410b
								void *data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = data;
Packit 34410b
	struct obex_session *session = transfer->session;
Packit 34410b
Packit 34410b
	return session->name != NULL;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean transfer_get_name(const GDBusPropertyTable *property,
Packit 34410b
					DBusMessageIter *iter, void *data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = data;
Packit 34410b
	struct obex_session *session = transfer->session;
Packit 34410b
Packit 34410b
	if (session->name == NULL)
Packit 34410b
		return FALSE;
Packit 34410b
Packit 34410b
	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &session->name);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean transfer_type_exists(const GDBusPropertyTable *property,
Packit 34410b
								void *data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = data;
Packit 34410b
	struct obex_session *session = transfer->session;
Packit 34410b
Packit 34410b
	return session->type != NULL;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean transfer_get_type(const GDBusPropertyTable *property,
Packit 34410b
					DBusMessageIter *iter, void *data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = data;
Packit 34410b
	struct obex_session *session = transfer->session;
Packit 34410b
Packit 34410b
	if (session->type == NULL)
Packit 34410b
		return FALSE;
Packit 34410b
Packit 34410b
	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &session->type);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean transfer_size_exists(const GDBusPropertyTable *property,
Packit 34410b
								void *data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = data;
Packit 34410b
	struct obex_session *session = transfer->session;
Packit 34410b
Packit 34410b
	return (session->size != OBJECT_SIZE_UNKNOWN &&
Packit 34410b
				session->size != OBJECT_SIZE_DELETE);
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean transfer_get_size(const GDBusPropertyTable *property,
Packit 34410b
					DBusMessageIter *iter, void *data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = data;
Packit 34410b
	struct obex_session *session = transfer->session;
Packit 34410b
Packit 34410b
	if (session->size == OBJECT_SIZE_UNKNOWN ||
Packit 34410b
				session->size == OBJECT_SIZE_DELETE)
Packit 34410b
		return FALSE;
Packit 34410b
Packit 34410b
	dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &session->size);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean transfer_time_exists(const GDBusPropertyTable *property,
Packit 34410b
								void *data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = data;
Packit 34410b
	struct obex_session *session = transfer->session;
Packit 34410b
Packit 34410b
	return session->time != 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean transfer_get_time(const GDBusPropertyTable *property,
Packit 34410b
					DBusMessageIter *iter, void *data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = data;
Packit 34410b
	struct obex_session *session = transfer->session;
Packit 34410b
	dbus_uint64_t time_u64;
Packit 34410b
Packit 34410b
	if (session->size == 0)
Packit 34410b
		return FALSE;
Packit 34410b
Packit 34410b
	time_u64 = session->time;
Packit 34410b
Packit 34410b
	dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &time_u64);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean transfer_filename_exists(const GDBusPropertyTable *property,
Packit 34410b
								void *data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = data;
Packit 34410b
	struct obex_session *session = transfer->session;
Packit 34410b
Packit 34410b
	return session->path != NULL;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean transfer_get_filename(const GDBusPropertyTable *property,
Packit 34410b
					DBusMessageIter *iter, void *data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = data;
Packit 34410b
	struct obex_session *session = transfer->session;
Packit 34410b
Packit 34410b
	if (session->path == NULL)
Packit 34410b
		return FALSE;
Packit 34410b
Packit 34410b
	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &session->path);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean transfer_get_transferred(const GDBusPropertyTable *property,
Packit 34410b
					DBusMessageIter *iter, void *data)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer = data;
Packit 34410b
	struct obex_session *session = transfer->session;
Packit 34410b
Packit 34410b
	dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64,
Packit 34410b
							&session->offset);
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static const GDBusMethodTable manager_methods[] = {
Packit 34410b
	{ GDBUS_METHOD("RegisterAgent",
Packit 34410b
			GDBUS_ARGS({ "agent", "o" }), NULL, register_agent) },
Packit 34410b
	{ GDBUS_METHOD("UnregisterAgent",
Packit 34410b
			GDBUS_ARGS({ "agent", "o" }), NULL, unregister_agent) },
Packit 34410b
	{ }
Packit 34410b
};
Packit 34410b
Packit 34410b
static const GDBusMethodTable transfer_methods[] = {
Packit 34410b
	{ GDBUS_METHOD("Cancel", NULL, NULL, transfer_cancel) },
Packit 34410b
	{ }
Packit 34410b
};
Packit 34410b
Packit 34410b
static const GDBusPropertyTable transfer_properties[] = {
Packit 34410b
	{ "Status", "s", transfer_get_status },
Packit 34410b
	{ "Session", "o", transfer_get_session },
Packit 34410b
	{ "Name", "s", transfer_get_name, NULL, transfer_name_exists },
Packit 34410b
	{ "Type", "s", transfer_get_type, NULL, transfer_type_exists },
Packit 34410b
	{ "Size", "t", transfer_get_size, NULL, transfer_size_exists },
Packit 34410b
	{ "Time", "t", transfer_get_time, NULL, transfer_time_exists },
Packit 34410b
	{ "Filename", "s", transfer_get_filename, NULL,
Packit 34410b
						transfer_filename_exists },
Packit 34410b
	{ "Transferred", "t", transfer_get_transferred },
Packit 34410b
	{ }
Packit 34410b
};
Packit 34410b
Packit 34410b
static const GDBusPropertyTable session_properties[] = {
Packit 34410b
	{ "Source", "s", get_source },
Packit 34410b
	{ "Destination", "s", get_destination },
Packit 34410b
	{ "Target", "s", get_target, NULL, session_target_exists },
Packit 34410b
	{ "Root", "s", get_root },
Packit 34410b
	{ }
Packit 34410b
};
Packit 34410b
Packit 34410b
gboolean manager_init(void)
Packit 34410b
{
Packit 34410b
	DBusError err;
Packit 34410b
Packit 34410b
	DBG("");
Packit 34410b
Packit 34410b
	dbus_error_init(&err;;
Packit 34410b
Packit 34410b
	connection = g_dbus_setup_bus(DBUS_BUS_SESSION, OBEXD_SERVICE, &err;;
Packit 34410b
	if (connection == NULL) {
Packit 34410b
		if (dbus_error_is_set(&err) == TRUE) {
Packit 34410b
			fprintf(stderr, "%s\n", err.message);
Packit 34410b
			dbus_error_free(&err;;
Packit 34410b
		} else
Packit 34410b
			fprintf(stderr, "Can't register with session bus\n");
Packit 34410b
		return FALSE;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	g_dbus_attach_object_manager(connection);
Packit 34410b
Packit 34410b
	return g_dbus_register_interface(connection, OBEX_BASE_PATH,
Packit 34410b
					OBEX_MANAGER_INTERFACE,
Packit 34410b
					manager_methods, NULL, NULL,
Packit 34410b
					NULL, NULL);
Packit 34410b
}
Packit 34410b
Packit 34410b
void manager_cleanup(void)
Packit 34410b
{
Packit 34410b
	DBG("");
Packit 34410b
Packit 34410b
	g_dbus_unregister_interface(connection, OBEX_BASE_PATH,
Packit 34410b
						OBEX_MANAGER_INTERFACE);
Packit 34410b
Packit 34410b
	/* FIXME: Release agent? */
Packit 34410b
Packit 34410b
	agent_free(agent);
Packit 34410b
Packit 34410b
	g_dbus_detach_object_manager(connection);
Packit 34410b
Packit 34410b
	dbus_connection_unref(connection);
Packit 34410b
}
Packit 34410b
Packit 34410b
void manager_emit_transfer_property(struct obex_transfer *transfer,
Packit 34410b
								char *name)
Packit 34410b
{
Packit 34410b
	if (!transfer->path)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	g_dbus_emit_property_changed(connection, transfer->path,
Packit 34410b
					TRANSFER_INTERFACE, name);
Packit 34410b
}
Packit 34410b
Packit 34410b
void manager_emit_transfer_started(struct obex_transfer *transfer)
Packit 34410b
{
Packit 34410b
	transfer->status = TRANSFER_STATUS_ACTIVE;
Packit 34410b
Packit 34410b
	manager_emit_transfer_property(transfer, "Status");
Packit 34410b
}
Packit 34410b
Packit 34410b
static void emit_transfer_completed(struct obex_transfer *transfer,
Packit 34410b
							gboolean success)
Packit 34410b
{
Packit 34410b
	if (transfer->path == NULL)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	transfer->status = success ? TRANSFER_STATUS_COMPLETE :
Packit 34410b
						TRANSFER_STATUS_ERROR;
Packit 34410b
Packit 34410b
	manager_emit_transfer_property(transfer, "Status");
Packit 34410b
}
Packit 34410b
Packit 34410b
static void transfer_free(struct obex_transfer *transfer)
Packit 34410b
{
Packit 34410b
	g_free(transfer->path);
Packit 34410b
	g_free(transfer);
Packit 34410b
}
Packit 34410b
Packit 34410b
struct obex_transfer *manager_register_transfer(struct obex_session *os)
Packit 34410b
{
Packit 34410b
	struct obex_transfer *transfer;
Packit 34410b
	static unsigned int id = 0;
Packit 34410b
Packit 34410b
	transfer = g_new0(struct obex_transfer, 1);
Packit 34410b
	transfer->path = g_strdup_printf("%s/session%u/transfer%u",
Packit 34410b
					SESSION_BASE_PATH, os->id, id++);
Packit 34410b
	transfer->session = os;
Packit 34410b
Packit 34410b
	if (!g_dbus_register_interface(connection, transfer->path,
Packit 34410b
				TRANSFER_INTERFACE,
Packit 34410b
				transfer_methods, NULL,
Packit 34410b
				transfer_properties, transfer, NULL)) {
Packit 34410b
		error("Cannot register Transfer interface.");
Packit 34410b
		transfer_free(transfer);
Packit 34410b
		return NULL;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	return transfer;
Packit 34410b
}
Packit 34410b
Packit 34410b
void manager_unregister_transfer(struct obex_transfer *transfer)
Packit 34410b
{
Packit 34410b
	struct obex_session *os;
Packit 34410b
Packit 34410b
	if (transfer == NULL)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	os = transfer->session;
Packit 34410b
Packit 34410b
	if (transfer->status == TRANSFER_STATUS_ACTIVE)
Packit 34410b
		emit_transfer_completed(transfer, os->offset == os->size);
Packit 34410b
Packit 34410b
	g_dbus_unregister_interface(connection, transfer->path,
Packit 34410b
							TRANSFER_INTERFACE);
Packit 34410b
Packit 34410b
	transfer_free(transfer);
Packit 34410b
}
Packit 34410b
Packit 34410b
static void agent_cancel(void)
Packit 34410b
{
Packit 34410b
	DBusMessage *msg;
Packit 34410b
Packit 34410b
	if (agent == NULL)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	msg = dbus_message_new_method_call(agent->bus_name, agent->path,
Packit 34410b
						AGENT_INTERFACE, "Cancel");
Packit 34410b
Packit 34410b
	g_dbus_send_message(connection, msg);
Packit 34410b
}
Packit 34410b
Packit 34410b
static void agent_reply(DBusPendingCall *call, void *user_data)
Packit 34410b
{
Packit 34410b
	DBusMessage *reply = dbus_pending_call_steal_reply(call);
Packit 34410b
	const char *name;
Packit 34410b
	DBusError derr;
Packit 34410b
	gboolean *got_reply = user_data;
Packit 34410b
Packit 34410b
	*got_reply = TRUE;
Packit 34410b
Packit 34410b
	/* Received a reply after the agent exited */
Packit 34410b
	if (!agent)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	agent->auth_pending = FALSE;
Packit 34410b
Packit 34410b
	dbus_error_init(&derr);
Packit 34410b
	if (dbus_set_error_from_message(&derr, reply)) {
Packit 34410b
		error("Agent replied with an error: %s, %s",
Packit 34410b
				derr.name, derr.message);
Packit 34410b
Packit 34410b
		if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY))
Packit 34410b
			agent_cancel();
Packit 34410b
Packit 34410b
		dbus_error_free(&derr);
Packit 34410b
		dbus_message_unref(reply);
Packit 34410b
		return;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (dbus_message_get_args(reply, NULL,
Packit 34410b
				DBUS_TYPE_STRING, &name,
Packit 34410b
				DBUS_TYPE_INVALID)) {
Packit 34410b
		/* Splits folder and name */
Packit Service d358a3
		const char *slash = strrchr(name, '/');
Packit 34410b
		DBG("Agent replied with %s", name);
Packit Service d358a3
		if (!slash) {
Packit Service d358a3
			agent->new_name = g_strdup(name);
Packit 34410b
			agent->new_folder = NULL;
Packit 34410b
		} else {
Packit Service d358a3
			agent->new_name = g_strdup(slash + 1);
Packit Service d358a3
			agent->new_folder = g_strndup(name, slash - name);
Packit 34410b
		}
Packit 34410b
	}
Packit 34410b
Packit 34410b
	dbus_message_unref(reply);
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean auth_error(GIOChannel *io, GIOCondition cond, void *user_data)
Packit 34410b
{
Packit 34410b
	agent->auth_pending = FALSE;
Packit 34410b
Packit 34410b
	return FALSE;
Packit 34410b
}
Packit 34410b
Packit 34410b
int manager_request_authorization(struct obex_transfer *transfer,
Packit 34410b
					char **new_folder, char **new_name)
Packit 34410b
{
Packit 34410b
	struct obex_session *os = transfer->session;
Packit 34410b
	DBusMessage *msg;
Packit 34410b
	DBusPendingCall *call;
Packit 34410b
	unsigned int watch;
Packit 34410b
	gboolean got_reply;
Packit 34410b
Packit 34410b
	if (!agent)
Packit 34410b
		return -1;
Packit 34410b
Packit 34410b
	if (agent->auth_pending)
Packit 34410b
		return -EPERM;
Packit 34410b
Packit 34410b
	if (!new_folder || !new_name)
Packit 34410b
		return -EINVAL;
Packit 34410b
Packit 34410b
	msg = dbus_message_new_method_call(agent->bus_name, agent->path,
Packit 34410b
							AGENT_INTERFACE,
Packit 34410b
							"AuthorizePush");
Packit 34410b
Packit 34410b
	dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &transfer->path,
Packit 34410b
							DBUS_TYPE_INVALID);
Packit 34410b
Packit 34410b
	if (!g_dbus_send_message_with_reply(connection, msg, &call, TIMEOUT)) {
Packit 34410b
		dbus_message_unref(msg);
Packit 34410b
		return -EPERM;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	dbus_message_unref(msg);
Packit 34410b
Packit 34410b
	agent->auth_pending = TRUE;
Packit 34410b
	got_reply = FALSE;
Packit 34410b
Packit 34410b
	/* Catches errors before authorization response comes */
Packit 34410b
	watch = g_io_add_watch_full(os->io, G_PRIORITY_DEFAULT,
Packit 34410b
			G_IO_HUP | G_IO_ERR | G_IO_NVAL,
Packit 34410b
			auth_error, NULL, NULL);
Packit 34410b
Packit 34410b
	dbus_pending_call_set_notify(call, agent_reply, &got_reply, NULL);
Packit 34410b
Packit 34410b
	/* Workaround: process events while agent doesn't reply */
Packit 34410b
	while (agent && agent->auth_pending)
Packit 34410b
		g_main_context_iteration(NULL, TRUE);
Packit 34410b
Packit 34410b
	g_source_remove(watch);
Packit 34410b
Packit 34410b
	if (!got_reply) {
Packit 34410b
		dbus_pending_call_cancel(call);
Packit 34410b
		agent_cancel();
Packit 34410b
	}
Packit 34410b
Packit 34410b
	dbus_pending_call_unref(call);
Packit 34410b
Packit 34410b
	if (!agent || !agent->new_name)
Packit 34410b
		return -EPERM;
Packit 34410b
Packit 34410b
	*new_folder = agent->new_folder;
Packit 34410b
	*new_name = agent->new_name;
Packit 34410b
	agent->new_folder = NULL;
Packit 34410b
	agent->new_name = NULL;
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
static DBusMessage *session_get_capabilities(DBusConnection *connection,
Packit 34410b
					DBusMessage *message, void *user_data)
Packit 34410b
{
Packit 34410b
	return not_supported(message);
Packit 34410b
}
Packit 34410b
Packit 34410b
static const GDBusMethodTable session_methods[] = {
Packit 34410b
	{ GDBUS_ASYNC_METHOD("GetCapabilities",
Packit 34410b
				NULL, GDBUS_ARGS({ "capabilities", "s" }),
Packit 34410b
				session_get_capabilities) },
Packit 34410b
	{ }
Packit 34410b
};
Packit 34410b
Packit 34410b
void manager_register_session(struct obex_session *os)
Packit 34410b
{
Packit 34410b
	char *path;
Packit 34410b
Packit 34410b
	path = g_strdup_printf("%s/session%u", SESSION_BASE_PATH, os->id);
Packit 34410b
Packit 34410b
	if (!g_dbus_register_interface(connection, path,
Packit 34410b
				SESSION_INTERFACE,
Packit 34410b
				session_methods, NULL,
Packit 34410b
				session_properties, os, NULL))
Packit 34410b
		error("Cannot register Session interface.");
Packit 34410b
Packit 34410b
	g_free(path);
Packit 34410b
}
Packit 34410b
Packit 34410b
void manager_unregister_session(struct obex_session *os)
Packit 34410b
{
Packit 34410b
	char *path;
Packit 34410b
Packit 34410b
	path = g_strdup_printf("%s/session%u", SESSION_BASE_PATH, os->id);
Packit 34410b
Packit 34410b
	g_dbus_unregister_interface(connection, path, SESSION_INTERFACE);
Packit 34410b
Packit 34410b
	g_free(path);
Packit 34410b
}
Packit 34410b
Packit 34410b
void manager_emit_transfer_progress(struct obex_transfer *transfer)
Packit 34410b
{
Packit 34410b
	manager_emit_transfer_property(transfer, "Transferred");
Packit 34410b
}
Packit 34410b
Packit 34410b
void manager_emit_transfer_completed(struct obex_transfer *transfer)
Packit 34410b
{
Packit 34410b
	struct obex_session *session;
Packit 34410b
Packit 34410b
	if (transfer == NULL)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	session = transfer->session;
Packit 34410b
Packit 34410b
	if (session == NULL || session->object == NULL)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	emit_transfer_completed(transfer, !session->aborted);
Packit 34410b
}
Packit 34410b
Packit 34410b
DBusConnection *manager_dbus_get_connection(void)
Packit 34410b
{
Packit 34410b
	if (connection == NULL)
Packit 34410b
		return NULL;
Packit 34410b
Packit 34410b
	return dbus_connection_ref(connection);
Packit 34410b
}