Blame sendto/main.c

Packit 8fb625
/*
Packit 8fb625
 *
Packit 8fb625
 *  BlueZ - Bluetooth protocol stack for Linux
Packit 8fb625
 *
Packit 8fb625
 *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org>
Packit 8fb625
 *  Copyright (C) 2013 Intel Corporation.
Packit 8fb625
 *
Packit 8fb625
 *
Packit 8fb625
 *  This program is free software; you can redistribute it and/or modify
Packit 8fb625
 *  it under the terms of the GNU General Public License as published by
Packit 8fb625
 *  the Free Software Foundation; either version 2 of the License, or
Packit 8fb625
 *  (at your option) any later version.
Packit 8fb625
 *
Packit 8fb625
 *  This program is distributed in the hope that it will be useful,
Packit 8fb625
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8fb625
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8fb625
 *  GNU General Public License for more details.
Packit 8fb625
 *
Packit 8fb625
 *  You should have received a copy of the GNU General Public License
Packit 8fb625
 *  along with this program; if not, write to the Free Software
Packit 8fb625
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Packit 8fb625
 *
Packit 8fb625
 */
Packit 8fb625
Packit 8fb625
#ifdef HAVE_CONFIG_H
Packit 8fb625
#include <config.h>
Packit 8fb625
#endif
Packit 8fb625
Packit 8fb625
#include <sys/time.h>
Packit 8fb625
Packit 8fb625
#include <glib/gi18n.h>
Packit 8fb625
#include <glib/gstdio.h>
Packit 8fb625
#include <gio/gio.h>
Packit 8fb625
#include <gtk/gtk.h>
Packit 8fb625
Packit 8fb625
#include <bluetooth-client.h>
Packit 8fb625
#include <bluetooth-chooser.h>
Packit 8fb625
Packit 8fb625
#define OBEX_SERVICE	"org.bluez.obex"
Packit 8fb625
#define OBEX_PATH	"/org/bluez/obex"
Packit 8fb625
#define TRANSFER_IFACE	"org.bluez.obex.Transfer1"
Packit 8fb625
#define OPP_IFACE	"org.bluez.obex.ObjectPush1"
Packit 8fb625
#define CLIENT_IFACE	"org.bluez.obex.Client1"
Packit 8fb625
Packit 8fb625
#define RESPONSE_RETRY 1
Packit 8fb625
Packit 8fb625
static GDBusConnection *conn = NULL;
Packit 8fb625
static GDBusProxy *client_proxy = NULL;
Packit 8fb625
static GDBusProxy *session = NULL;
Packit 8fb625
static GDBusProxy *current_transfer = NULL;
Packit 8fb625
static GCancellable *cancellable = NULL;
Packit 8fb625
Packit 8fb625
static GtkWidget *dialog;
Packit 8fb625
static GtkWidget *label_from;
Packit 8fb625
static GtkWidget *image_status;
Packit 8fb625
static GtkWidget *label_status;
Packit 8fb625
static GtkWidget *progress;
Packit 8fb625
Packit 8fb625
static gchar *option_device = NULL;
Packit 8fb625
static gchar *option_device_name = NULL;
Packit 8fb625
static gchar **option_files = NULL;
Packit 8fb625
Packit 8fb625
static guint64 current_size = 0;
Packit 8fb625
static guint64 total_size = 0;
Packit 8fb625
static guint64 total_sent = 0;
Packit 8fb625
Packit 8fb625
static int file_count = 0;
Packit 8fb625
static int file_index = 0;
Packit 8fb625
Packit 8fb625
static gint64 first_update = 0;
Packit 8fb625
static gint64 last_update = 0;
Packit 8fb625
Packit 8fb625
static void on_transfer_properties (GVariant *props);
Packit 8fb625
static void on_transfer_progress (guint64 transferred);
Packit 8fb625
static void on_transfer_complete (void);
Packit 8fb625
static void on_transfer_error (void);
Packit 8fb625
Packit 8fb625
static gint64
Packit 8fb625
get_system_time (void)
Packit 8fb625
{
Packit 8fb625
	struct timeval tmp;
Packit 8fb625
Packit 8fb625
	gettimeofday(&tmp, NULL);
Packit 8fb625
Packit 8fb625
	return (gint64) tmp.tv_usec +
Packit 8fb625
		(gint64) tmp.tv_sec * G_GINT64_CONSTANT(1000000);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
update_from_label (void)
Packit 8fb625
{
Packit 8fb625
	char *filename = option_files[file_index];
Packit 8fb625
	GFile *file, *dir;
Packit 8fb625
	char *text, *markup;
Packit 8fb625
Packit 8fb625
	file = g_file_new_for_path (filename);
Packit 8fb625
	dir = g_file_get_parent (file);
Packit 8fb625
	g_object_unref (file);
Packit 8fb625
	if (g_file_has_uri_scheme (dir, "file") != FALSE) {
Packit 8fb625
		text = g_file_get_path (dir);
Packit 8fb625
	} else {
Packit 8fb625
		text = g_file_get_uri (dir);
Packit 8fb625
	}
Packit 8fb625
	markup = g_markup_escape_text (text, -1);
Packit 8fb625
	g_free (text);
Packit 8fb625
	g_object_unref (dir);
Packit 8fb625
	gtk_label_set_markup (GTK_LABEL (label_from), markup);
Packit 8fb625
	g_free (markup);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static char *
Packit 8fb625
cleanup_error (GError *error)
Packit 8fb625
{
Packit 8fb625
	char *remote_error;
Packit 8fb625
Packit 8fb625
	if (!error || *error->message == '\0')
Packit 8fb625
		return g_strdup (_("An unknown error occurred"));
Packit 8fb625
	if (g_dbus_error_is_remote_error (error) == FALSE)
Packit 8fb625
		return g_strdup (error->message);
Packit 8fb625
Packit 8fb625
	remote_error = g_dbus_error_get_remote_error (error);
Packit 8fb625
	g_debug ("Remote error is: %s", remote_error);
Packit 8fb625
	g_free (remote_error);
Packit 8fb625
Packit 8fb625
	g_dbus_error_strip_remote_error (error);
Packit 8fb625
	g_debug ("Error message is: %s", error->message);
Packit 8fb625
Packit 8fb625
	/* And now, take advantage of the fact that obexd isn't translated */
Packit 8fb625
	if (g_strcmp0 (error->message, "Unable to find service record") == 0) {
Packit 8fb625
		return g_strdup (_("Make sure that the remote device is switched on and that it accepts Bluetooth connections"));
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	return g_strdup (error->message);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
handle_error (GError *error)
Packit 8fb625
{
Packit 8fb625
	char *message;
Packit 8fb625
Packit 8fb625
	message = cleanup_error (error);
Packit 8fb625
Packit 8fb625
	gtk_widget_show (image_status);
Packit 8fb625
	gtk_label_set_markup (GTK_LABEL (label_status), message);
Packit 8fb625
	g_clear_error (&error);
Packit 8fb625
	g_free (message);
Packit 8fb625
Packit 8fb625
	/* Clear the progress bar as it may be saying 'Connecting' or
Packit 8fb625
	 * 'Sending file 1 of 1' which is not true. */
Packit 8fb625
	gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progress), "");
Packit 8fb625
Packit 8fb625
	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), RESPONSE_RETRY, TRUE);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
transfer_properties_changed (GDBusProxy *proxy,
Packit 8fb625
			     GVariant *changed_properties,
Packit 8fb625
			     GStrv invalidated_properties,
Packit 8fb625
			     gpointer user_data)
Packit 8fb625
{
Packit 8fb625
	GVariantIter iter;
Packit 8fb625
	const char *key;
Packit 8fb625
	GVariant *value;
Packit 8fb625
Packit 8fb625
	g_variant_iter_init (&iter, changed_properties);
Packit 8fb625
	while (g_variant_iter_next (&iter, "{&sv}", &key, &value)) {
Packit 8fb625
		if (g_str_equal (key, "Status")) {
Packit 8fb625
			const char *status;
Packit 8fb625
Packit 8fb625
			status = g_variant_get_string (value, NULL);
Packit 8fb625
Packit 8fb625
			if (g_str_equal (status, "complete")) {
Packit 8fb625
				on_transfer_complete ();
Packit 8fb625
			} else if (g_str_equal (status, "error")) {
Packit 8fb625
				on_transfer_error ();
Packit 8fb625
			}
Packit 8fb625
		} else if (g_str_equal (key, "Transferred")) {
Packit 8fb625
			guint64 transferred = g_variant_get_uint64 (value);
Packit 8fb625
Packit 8fb625
			on_transfer_progress (transferred);
Packit 8fb625
		}
Packit 8fb625
Packit 8fb625
		g_variant_unref (value);
Packit 8fb625
	}
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
transfer_proxy (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
Packit 8fb625
{
Packit 8fb625
	GError *error = NULL;
Packit 8fb625
Packit 8fb625
	current_transfer = g_dbus_proxy_new_finish (res, &error);
Packit 8fb625
Packit 8fb625
	if (current_transfer == NULL) {
Packit 8fb625
		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
Packit 8fb625
			g_error_free (error);
Packit 8fb625
			return;
Packit 8fb625
		}
Packit 8fb625
Packit 8fb625
		handle_error (error);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	g_signal_connect (G_OBJECT (current_transfer), "g-properties-changed",
Packit 8fb625
		G_CALLBACK (transfer_properties_changed), NULL);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
transfer_created (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
Packit 8fb625
{
Packit 8fb625
	GError *error = NULL;
Packit 8fb625
	GVariant *variant, *properties;
Packit 8fb625
	const char *transfer;
Packit 8fb625
Packit 8fb625
	variant = g_dbus_proxy_call_finish (proxy, res, &error);
Packit 8fb625
Packit 8fb625
	if (variant == NULL) {
Packit 8fb625
		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
Packit 8fb625
			g_error_free (error);
Packit 8fb625
			return;
Packit 8fb625
		}
Packit 8fb625
Packit 8fb625
		handle_error (error);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progress), NULL);
Packit 8fb625
Packit 8fb625
	first_update = get_system_time ();
Packit 8fb625
Packit 8fb625
	g_variant_get (variant, "(&o@a{sv})", &transfer, &properties);
Packit 8fb625
Packit 8fb625
	on_transfer_properties (properties);
Packit 8fb625
Packit 8fb625
	g_dbus_proxy_new (conn,
Packit 8fb625
			  G_DBUS_PROXY_FLAGS_NONE,
Packit 8fb625
			  NULL,
Packit 8fb625
			  OBEX_SERVICE,
Packit 8fb625
			  transfer,
Packit 8fb625
			  TRANSFER_IFACE,
Packit 8fb625
			  cancellable,
Packit 8fb625
			  (GAsyncReadyCallback) transfer_proxy,
Packit 8fb625
			  NULL);
Packit 8fb625
Packit 8fb625
	g_variant_unref (properties);
Packit 8fb625
	g_variant_unref (variant);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
send_next_file (void)
Packit 8fb625
{
Packit 8fb625
	update_from_label ();
Packit 8fb625
Packit 8fb625
	g_dbus_proxy_call (session,
Packit 8fb625
			   "SendFile",
Packit 8fb625
			   g_variant_new ("(s)", option_files[file_index]),
Packit 8fb625
			   G_DBUS_CALL_FLAGS_NONE,
Packit 8fb625
			   -1,
Packit 8fb625
			   cancellable,
Packit 8fb625
			   (GAsyncReadyCallback) transfer_created,
Packit 8fb625
			   NULL);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
session_proxy (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
Packit 8fb625
{
Packit 8fb625
	GError *error = NULL;
Packit 8fb625
Packit 8fb625
	g_clear_object (&session);
Packit 8fb625
	session = g_dbus_proxy_new_finish (res, &error);
Packit 8fb625
Packit 8fb625
	if (session == NULL) {
Packit 8fb625
		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
Packit 8fb625
			g_error_free (error);
Packit 8fb625
			return;
Packit 8fb625
		}
Packit 8fb625
Packit 8fb625
		handle_error (error);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	send_next_file ();
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
session_created (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
Packit 8fb625
{
Packit 8fb625
	GError *error = NULL;
Packit 8fb625
	GVariant *variant;
Packit 8fb625
	const char *session;
Packit 8fb625
Packit 8fb625
	variant = g_dbus_proxy_call_finish (proxy, res, &error);
Packit 8fb625
Packit 8fb625
	if (variant == NULL) {
Packit 8fb625
		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
Packit 8fb625
			g_error_free (error);
Packit 8fb625
			return;
Packit 8fb625
		}
Packit 8fb625
Packit 8fb625
		handle_error (error);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	g_variant_get (variant, "(&o)", &session);
Packit 8fb625
Packit 8fb625
	g_dbus_proxy_new (conn,
Packit 8fb625
			  G_DBUS_PROXY_FLAGS_NONE,
Packit 8fb625
			  NULL,
Packit 8fb625
			  OBEX_SERVICE,
Packit 8fb625
			  session,
Packit 8fb625
			  OPP_IFACE,
Packit 8fb625
			  cancellable,
Packit 8fb625
			  (GAsyncReadyCallback) session_proxy,
Packit 8fb625
			  NULL);
Packit 8fb625
Packit 8fb625
	g_variant_unref (variant);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
send_files (void)
Packit 8fb625
{
Packit 8fb625
	GVariant *parameters;
Packit 8fb625
	GVariantBuilder *builder;
Packit 8fb625
Packit 8fb625
	builder = g_variant_builder_new (G_VARIANT_TYPE_DICTIONARY);
Packit 8fb625
	g_variant_builder_add (builder, "{sv}", "Target",
Packit 8fb625
						g_variant_new_string ("opp"));
Packit 8fb625
Packit 8fb625
	parameters = g_variant_new ("(sa{sv})", option_device, builder);
Packit 8fb625
Packit 8fb625
	g_dbus_proxy_call (client_proxy,
Packit 8fb625
			   "CreateSession",
Packit 8fb625
			   parameters,
Packit 8fb625
			   G_DBUS_CALL_FLAGS_NONE,
Packit 8fb625
			   -1,
Packit 8fb625
			   cancellable,
Packit 8fb625
			   (GAsyncReadyCallback) session_created,
Packit 8fb625
			   NULL);
Packit 8fb625
Packit 8fb625
	g_variant_builder_unref (builder);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gchar *filename_to_path(const gchar *filename)
Packit 8fb625
{
Packit 8fb625
	GFile *file;
Packit 8fb625
	gchar *path;
Packit 8fb625
Packit 8fb625
	file = g_file_new_for_commandline_arg(filename);
Packit 8fb625
	path = g_file_get_path(file);
Packit 8fb625
	g_object_unref(file);
Packit 8fb625
Packit 8fb625
	return path;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gchar *format_time(gint seconds)
Packit 8fb625
{
Packit 8fb625
	gint hours, minutes;
Packit 8fb625
Packit 8fb625
	if (seconds < 0)
Packit 8fb625
		seconds = 0;
Packit 8fb625
Packit 8fb625
	if (seconds < 60)
Packit 8fb625
		return g_strdup_printf(ngettext("%'d second",
Packit 8fb625
					"%'d seconds", seconds), seconds);
Packit 8fb625
Packit 8fb625
	if (seconds < 60 * 60) {
Packit 8fb625
		minutes = (seconds + 30) / 60;
Packit 8fb625
		return g_strdup_printf(ngettext("%'d minute",
Packit 8fb625
					"%'d minutes", minutes), minutes);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	hours = seconds / (60 * 60);
Packit 8fb625
Packit 8fb625
	if (seconds < 60 * 60 * 4) {
Packit 8fb625
		gchar *res, *h, *m;
Packit 8fb625
Packit 8fb625
		minutes = (seconds - hours * 60 * 60 + 30) / 60;
Packit 8fb625
Packit 8fb625
		h = g_strdup_printf(ngettext("%'d hour",
Packit 8fb625
					"%'d hours", hours), hours);
Packit 8fb625
		m = g_strdup_printf(ngettext("%'d minute",
Packit 8fb625
					"%'d minutes", minutes), minutes);
Packit 8fb625
		res = g_strconcat(h, ", ", m, NULL);
Packit 8fb625
		g_free(h);
Packit 8fb625
		g_free(m);
Packit 8fb625
		return res;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	return g_strdup_printf(ngettext("approximately %'d hour",
Packit 8fb625
				"approximately %'d hours", hours), hours);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void response_callback(GtkWidget *dialog,
Packit 8fb625
					gint response, gpointer user_data)
Packit 8fb625
{
Packit 8fb625
	if (response == RESPONSE_RETRY) {
Packit 8fb625
		/* Reset buttons */
Packit 8fb625
		gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), RESPONSE_RETRY, FALSE);
Packit 8fb625
Packit 8fb625
		/* Reset status and progress bar */
Packit 8fb625
		gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progress),
Packit 8fb625
					  _("Connecting…"));
Packit 8fb625
		gtk_label_set_text (GTK_LABEL (label_status), "");
Packit 8fb625
		gtk_widget_hide (image_status);
Packit 8fb625
Packit 8fb625
		/* If we have a session, we don't need to create another one. */
Packit 8fb625
		if (session)
Packit 8fb625
			send_next_file ();
Packit 8fb625
		else
Packit 8fb625
			send_files ();
Packit 8fb625
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	/* Cancel any ongoing dbus calls we may have */
Packit 8fb625
	g_cancellable_cancel (cancellable);
Packit 8fb625
Packit 8fb625
	if (current_transfer != NULL) {
Packit 8fb625
		g_dbus_proxy_call (current_transfer,
Packit 8fb625
				   "Cancel",
Packit 8fb625
				   NULL,
Packit 8fb625
				   G_DBUS_CALL_FLAGS_NONE,
Packit 8fb625
				   -1,
Packit 8fb625
				   NULL,
Packit 8fb625
				   (GAsyncReadyCallback) NULL,
Packit 8fb625
				   NULL);
Packit 8fb625
		g_object_unref (current_transfer);
Packit 8fb625
		current_transfer = NULL;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	gtk_widget_destroy(dialog);
Packit 8fb625
	gtk_main_quit();
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void create_window(void)
Packit 8fb625
{
Packit 8fb625
	GtkWidget *vbox, *hbox;
Packit 8fb625
	GtkWidget *table;
Packit 8fb625
	GtkWidget *label;
Packit 8fb625
	gchar *text;
Packit 8fb625
Packit 8fb625
	dialog = g_object_new (GTK_TYPE_DIALOG,
Packit 8fb625
			       "use-header-bar", 1,
Packit 8fb625
			       "title", _("Bluetooth File Transfer"),
Packit 8fb625
			       NULL);
Packit 8fb625
	gtk_dialog_add_buttons(GTK_DIALOG (dialog),
Packit 8fb625
			       _("_Cancel"), GTK_RESPONSE_CANCEL,
Packit 8fb625
			       _("_Retry"), RESPONSE_RETRY,
Packit 8fb625
			       NULL);
Packit 8fb625
	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), RESPONSE_RETRY, FALSE);
Packit 8fb625
	gtk_window_set_type_hint(GTK_WINDOW(dialog),
Packit 8fb625
				 GDK_WINDOW_TYPE_HINT_NORMAL);
Packit 8fb625
	gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
Packit 8fb625
	gtk_window_set_default_size(GTK_WINDOW(dialog), 400, -1);
Packit 8fb625
	gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
Packit 8fb625
Packit 8fb625
	vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
Packit 8fb625
	gtk_box_set_spacing(GTK_BOX(vbox), 6);
Packit 8fb625
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
Packit 8fb625
	gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
Packit 8fb625
	                   vbox);
Packit 8fb625
Packit 8fb625
	table = gtk_grid_new();
Packit 8fb625
	gtk_grid_set_column_spacing(GTK_GRID(table), 4);
Packit 8fb625
	gtk_grid_set_row_spacing(GTK_GRID(table), 4);
Packit 8fb625
	gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 9);
Packit 8fb625
Packit 8fb625
	label = gtk_label_new(NULL);
Packit 8fb625
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
Packit 8fb625
	text = g_markup_printf_escaped("%s", _("From:"));
Packit 8fb625
	gtk_label_set_markup(GTK_LABEL(label), text);
Packit 8fb625
	g_free(text);
Packit 8fb625
	gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
Packit 8fb625
Packit 8fb625
	label_from = gtk_label_new(NULL);
Packit 8fb625
	gtk_misc_set_alignment(GTK_MISC(label_from), 0, 0.5);
Packit 8fb625
	gtk_label_set_ellipsize(GTK_LABEL(label_from), PANGO_ELLIPSIZE_MIDDLE);
Packit 8fb625
	gtk_grid_attach(GTK_GRID(table), label_from, 1, 0, 1, 1);
Packit 8fb625
Packit 8fb625
	update_from_label ();
Packit 8fb625
Packit 8fb625
	label = gtk_label_new(NULL);
Packit 8fb625
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
Packit 8fb625
	text = g_markup_printf_escaped("%s", _("To:"));
Packit 8fb625
	gtk_label_set_markup(GTK_LABEL(label), text);
Packit 8fb625
	g_free(text);
Packit 8fb625
	gtk_grid_attach(GTK_GRID(table), label, 0, 1, 1, 1);
Packit 8fb625
Packit 8fb625
	label = gtk_label_new(NULL);
Packit 8fb625
	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
Packit 8fb625
	gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
Packit 8fb625
	gtk_label_set_text(GTK_LABEL(label), option_device_name);
Packit 8fb625
	gtk_grid_attach(GTK_GRID(table), label, 1, 1, 1, 1);
Packit 8fb625
Packit 8fb625
	progress = gtk_progress_bar_new();
Packit 8fb625
	gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR (progress), TRUE);
Packit 8fb625
	gtk_progress_bar_set_ellipsize(GTK_PROGRESS_BAR(progress),
Packit 8fb625
							PANGO_ELLIPSIZE_END);
Packit 8fb625
	gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress),
Packit 8fb625
							_("Connecting…"));
Packit 8fb625
	gtk_box_pack_start(GTK_BOX(vbox), progress, TRUE, TRUE, 0);
Packit 8fb625
Packit 8fb625
	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
Packit 8fb625
Packit 8fb625
	image_status = gtk_image_new_from_icon_name ("dialog-warning", GTK_ICON_SIZE_MENU);
Packit 8fb625
	gtk_widget_set_no_show_all (image_status, TRUE);
Packit 8fb625
	gtk_box_pack_start(GTK_BOX (hbox), image_status, FALSE, FALSE, 4);
Packit 8fb625
Packit 8fb625
	label_status = gtk_label_new(NULL);
Packit 8fb625
	gtk_misc_set_alignment(GTK_MISC(label_status), 0, 0.5);
Packit 8fb625
	gtk_label_set_line_wrap(GTK_LABEL(label_status), TRUE);
Packit 8fb625
	gtk_box_pack_start(GTK_BOX (hbox), label_status, TRUE, TRUE, 4);
Packit 8fb625
Packit 8fb625
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);
Packit 8fb625
Packit 8fb625
	g_signal_connect(G_OBJECT(dialog), "response",
Packit 8fb625
				G_CALLBACK(response_callback), NULL);
Packit 8fb625
Packit 8fb625
	gtk_widget_show_all(dialog);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gchar *get_device_name(const gchar *address)
Packit 8fb625
{
Packit 8fb625
	BluetoothClient *client;
Packit 8fb625
	GtkTreeModel *model;
Packit 8fb625
	GtkTreeIter iter;
Packit 8fb625
	gboolean cont;
Packit 8fb625
	char *found_name;
Packit 8fb625
Packit 8fb625
	found_name = NULL;
Packit 8fb625
	client = bluetooth_client_new ();
Packit 8fb625
	model = bluetooth_client_get_model (client);
Packit 8fb625
	if (model == NULL) {
Packit 8fb625
		g_object_unref (client);
Packit 8fb625
		return NULL;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	cont = gtk_tree_model_get_iter_first(model, &iter);
Packit 8fb625
	while (cont != FALSE) {
Packit 8fb625
		char *bdaddr, *name;
Packit 8fb625
Packit 8fb625
		gtk_tree_model_get(model, &iter,
Packit 8fb625
				   BLUETOOTH_COLUMN_ADDRESS, &bdaddr,
Packit 8fb625
				   BLUETOOTH_COLUMN_ALIAS, &name,
Packit 8fb625
				   -1);
Packit 8fb625
		if (g_strcmp0 (bdaddr, address) == 0) {
Packit 8fb625
			g_free (bdaddr);
Packit 8fb625
			found_name = name;
Packit 8fb625
			break;
Packit 8fb625
		}
Packit 8fb625
		g_free (bdaddr);
Packit 8fb625
		g_free (name);
Packit 8fb625
Packit 8fb625
		cont = gtk_tree_model_iter_next(model, &iter);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	g_object_unref (model);
Packit 8fb625
	g_object_unref (client);
Packit 8fb625
Packit 8fb625
	return found_name;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
on_transfer_properties (GVariant *props)
Packit 8fb625
{
Packit 8fb625
	char *filename = option_files[file_index];
Packit 8fb625
	char *basename, *text, *markup;
Packit 8fb625
	GVariant *size;
Packit 8fb625
Packit 8fb625
	size = g_variant_lookup_value (props, "Size", G_VARIANT_TYPE_UINT64);
Packit 8fb625
	if (size) {
Packit 8fb625
		current_size = g_variant_get_uint64 (size);
Packit 8fb625
		last_update = get_system_time ();
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	basename = g_path_get_basename(filename);
Packit 8fb625
	text = g_strdup_printf(_("Sending %s"), basename);
Packit 8fb625
	g_free(basename);
Packit 8fb625
	markup = g_markup_printf_escaped("%s", text);
Packit 8fb625
	gtk_label_set_markup(GTK_LABEL(label_status), markup);
Packit 8fb625
	g_free(markup);
Packit 8fb625
	g_free(text);
Packit 8fb625
Packit 8fb625
	text = g_strdup_printf(_("Sending file %d of %d"),
Packit 8fb625
						file_index + 1, file_count);
Packit 8fb625
	gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), text);
Packit 8fb625
	g_free(text);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
on_transfer_progress (guint64 transferred)
Packit 8fb625
{
Packit 8fb625
	gint64 current_time;
Packit 8fb625
	gint elapsed_time;
Packit 8fb625
	gint remaining_time;
Packit 8fb625
	gint transfer_rate;
Packit 8fb625
	guint64 current_sent;
Packit 8fb625
	gdouble fraction;
Packit 8fb625
	gchar *time, *rate, *file, *text;
Packit 8fb625
Packit 8fb625
	current_sent = total_sent + transferred;
Packit 8fb625
	if (total_size == 0)
Packit 8fb625
		fraction = 0.0;
Packit 8fb625
	else
Packit 8fb625
		fraction = (gdouble) current_sent / (gdouble) total_size;
Packit 8fb625
	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction);
Packit 8fb625
Packit 8fb625
	current_time = get_system_time();
Packit 8fb625
	elapsed_time = (current_time - first_update) / 1000000;
Packit 8fb625
Packit 8fb625
	if (current_time < last_update + 1000000)
Packit 8fb625
		return;
Packit 8fb625
Packit 8fb625
	last_update = current_time;
Packit 8fb625
Packit 8fb625
	if (elapsed_time == 0)
Packit 8fb625
		return;
Packit 8fb625
Packit 8fb625
	transfer_rate = current_sent / elapsed_time;
Packit 8fb625
Packit 8fb625
	if (transfer_rate == 0)
Packit 8fb625
		return;
Packit 8fb625
Packit 8fb625
	remaining_time = (total_size - current_sent) / transfer_rate;
Packit 8fb625
Packit 8fb625
	time = format_time(remaining_time);
Packit 8fb625
Packit 8fb625
	if (transfer_rate >= 3000)
Packit 8fb625
		rate = g_strdup_printf(_("%d kB/s"), transfer_rate / 1000);
Packit 8fb625
	else
Packit 8fb625
		rate = g_strdup_printf(_("%d B/s"), transfer_rate);
Packit 8fb625
Packit 8fb625
	file = g_strdup_printf(_("Sending file %d of %d"),
Packit 8fb625
						file_index + 1, file_count);
Packit 8fb625
	text = g_strdup_printf("%s (%s, %s)", file, rate, time);
Packit 8fb625
	g_free(file);
Packit 8fb625
	g_free(rate);
Packit 8fb625
	g_free(time);
Packit 8fb625
	gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), text);
Packit 8fb625
	g_free(text);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
on_transfer_complete (void)
Packit 8fb625
{
Packit 8fb625
	total_sent += current_size;
Packit 8fb625
Packit 8fb625
	file_index++;
Packit 8fb625
Packit 8fb625
	/* And we're done with the transfer */
Packit 8fb625
	g_object_unref (current_transfer);
Packit 8fb625
	current_transfer = NULL;
Packit 8fb625
Packit 8fb625
	if (file_index == file_count) {
Packit 8fb625
		GtkWidget *button;
Packit 8fb625
		char *complete;
Packit 8fb625
Packit 8fb625
		gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), 1.0);
Packit 8fb625
Packit 8fb625
		gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), "");
Packit 8fb625
Packit 8fb625
		complete = g_strdup_printf (ngettext ("%u transfer complete",
Packit 8fb625
						      "%u transfers complete",
Packit 8fb625
						      file_count), file_count);
Packit 8fb625
		gtk_label_set_text (GTK_LABEL (label_status), complete);
Packit 8fb625
		g_free (complete);
Packit 8fb625
Packit 8fb625
		button = gtk_dialog_get_widget_for_response(GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
Packit 8fb625
		gtk_button_set_label (GTK_BUTTON (button), _("_Close"));
Packit 8fb625
	} else {
Packit 8fb625
		send_next_file ();
Packit 8fb625
	}
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
on_transfer_error (void)
Packit 8fb625
{
Packit 8fb625
	gtk_widget_show (image_status);
Packit 8fb625
	gtk_label_set_markup (GTK_LABEL (label_status), _("There was an error"));
Packit 8fb625
Packit 8fb625
	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), RESPONSE_RETRY, TRUE);
Packit 8fb625
Packit 8fb625
	g_object_unref (current_transfer);
Packit 8fb625
	current_transfer = NULL;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
select_device_changed(BluetoothChooser *sel,
Packit 8fb625
		      char *address,
Packit 8fb625
		      gpointer user_data)
Packit 8fb625
{
Packit 8fb625
	GtkDialog *dialog = user_data;
Packit 8fb625
	char *icon;
Packit 8fb625
Packit 8fb625
	if (address == NULL)
Packit 8fb625
		goto bail;
Packit 8fb625
Packit 8fb625
	icon = bluetooth_chooser_get_selected_device_icon (sel);
Packit 8fb625
	if (icon == NULL)
Packit 8fb625
		goto bail;
Packit 8fb625
Packit 8fb625
	/* Apple's device don't have OBEX */
Packit 8fb625
	if (g_str_equal (icon, "phone-apple-iphone"))
Packit 8fb625
		goto bail;
Packit 8fb625
Packit 8fb625
	gtk_dialog_set_response_sensitive (dialog,
Packit 8fb625
					   GTK_RESPONSE_ACCEPT, TRUE);
Packit 8fb625
	return;
Packit 8fb625
Packit 8fb625
bail:
Packit 8fb625
	gtk_dialog_set_response_sensitive (dialog,
Packit 8fb625
					   GTK_RESPONSE_ACCEPT, FALSE);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
select_device_activated(BluetoothChooser *sel,
Packit 8fb625
			char *address,
Packit 8fb625
			gpointer user_data)
Packit 8fb625
{
Packit 8fb625
	GtkDialog *dialog = user_data;
Packit 8fb625
Packit 8fb625
	gtk_dialog_response(dialog, GTK_RESPONSE_ACCEPT);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static char *
Packit 8fb625
show_browse_dialog (char **device_name)
Packit 8fb625
{
Packit 8fb625
	GtkWidget *dialog, *selector, *send_button, *content_area;
Packit 8fb625
	char *bdaddr;
Packit 8fb625
	int response_id;
Packit 8fb625
	GtkStyleContext *context;
Packit 8fb625
Packit 8fb625
	dialog = g_object_new (GTK_TYPE_DIALOG,
Packit 8fb625
			       "title", _("Select device to send to"),
Packit 8fb625
			       "use-header-bar", 1,
Packit 8fb625
			       NULL);
Packit 8fb625
	gtk_dialog_add_buttons(GTK_DIALOG (dialog),
Packit 8fb625
			       _("_Cancel"), GTK_RESPONSE_CANCEL,
Packit 8fb625
			       _("_Send"), GTK_RESPONSE_ACCEPT,
Packit 8fb625
			       NULL);
Packit 8fb625
	gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_NORMAL);
Packit 8fb625
	send_button = gtk_dialog_get_widget_for_response(GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
Packit 8fb625
	context = gtk_widget_get_style_context(send_button);
Packit 8fb625
	gtk_style_context_add_class (context, "suggested-action");
Packit 8fb625
Packit 8fb625
	gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog),
Packit 8fb625
					  GTK_RESPONSE_ACCEPT, FALSE);
Packit 8fb625
	gtk_window_set_default_size(GTK_WINDOW(dialog), 480, 400);
Packit 8fb625
Packit 8fb625
	gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
Packit 8fb625
	content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
Packit 8fb625
	gtk_box_set_spacing (GTK_BOX (content_area), 2);
Packit 8fb625
Packit 8fb625
	selector = bluetooth_chooser_new();
Packit 8fb625
	gtk_container_set_border_width(GTK_CONTAINER(selector), 5);
Packit 8fb625
	gtk_widget_show(selector);
Packit 8fb625
	g_object_set(selector,
Packit 8fb625
		     "show-searching", TRUE,
Packit 8fb625
		     "show-device-category", TRUE,
Packit 8fb625
		     "show-device-type", TRUE,
Packit 8fb625
		     NULL);
Packit 8fb625
	g_signal_connect(selector, "selected-device-changed",
Packit 8fb625
			 G_CALLBACK(select_device_changed), dialog);
Packit 8fb625
	g_signal_connect(selector, "selected-device-activated",
Packit 8fb625
			 G_CALLBACK(select_device_activated), dialog);
Packit 8fb625
	gtk_box_pack_start (GTK_BOX (content_area), selector, TRUE, TRUE, 0);
Packit 8fb625
	bluetooth_chooser_start_discovery (BLUETOOTH_CHOOSER (selector));
Packit 8fb625
Packit 8fb625
	bdaddr = NULL;
Packit 8fb625
	response_id = gtk_dialog_run (GTK_DIALOG (dialog));
Packit 8fb625
	if (response_id == GTK_RESPONSE_ACCEPT) {
Packit 8fb625
		bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (selector));
Packit 8fb625
		*device_name = bluetooth_chooser_get_selected_device_name (BLUETOOTH_CHOOSER (selector));
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	gtk_widget_destroy (dialog);
Packit 8fb625
Packit 8fb625
	return bdaddr;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static char **
Packit 8fb625
show_select_dialog(void)
Packit 8fb625
{
Packit 8fb625
	GtkWidget *dialog, *button;
Packit 8fb625
	gchar **files = NULL;
Packit 8fb625
	GtkStyleContext *context;
Packit 8fb625
Packit 8fb625
	dialog = g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
Packit 8fb625
			       "title", _("Choose files to send"),
Packit 8fb625
			       "action", GTK_FILE_CHOOSER_ACTION_OPEN,
Packit 8fb625
			       "use-header-bar", 1,
Packit 8fb625
			       NULL);
Packit 8fb625
	gtk_dialog_add_buttons(GTK_DIALOG (dialog),
Packit 8fb625
			       _("_Cancel"), GTK_RESPONSE_CANCEL,
Packit 8fb625
			       _("Select"), GTK_RESPONSE_ACCEPT, NULL);
Packit 8fb625
	gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_NORMAL);
Packit 8fb625
	gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
Packit 8fb625
Packit 8fb625
	button = gtk_dialog_get_widget_for_response(GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
Packit 8fb625
	context = gtk_widget_get_style_context(button);
Packit 8fb625
	gtk_style_context_add_class (context, "suggested-action");
Packit 8fb625
Packit 8fb625
	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
Packit 8fb625
		GSList *list, *filenames;
Packit 8fb625
		int i;
Packit 8fb625
Packit 8fb625
		filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
Packit 8fb625
Packit 8fb625
		files = g_new(gchar *, g_slist_length(filenames) + 1);
Packit 8fb625
Packit 8fb625
		for (list = filenames, i = 0; list; list = list->next, i++)
Packit 8fb625
			files[i] = list->data;
Packit 8fb625
		files[i] = NULL;
Packit 8fb625
Packit 8fb625
		g_slist_free(filenames);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	gtk_widget_destroy(dialog);
Packit 8fb625
Packit 8fb625
	return files;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static GOptionEntry options[] = {
Packit 8fb625
	{ "device", 0, 0, G_OPTION_ARG_STRING, &option_device,
Packit 8fb625
				N_("Remote device to use"), N_("ADDRESS") },
Packit 8fb625
	{ "name", 0, 0, G_OPTION_ARG_STRING, &option_device_name,
Packit 8fb625
				N_("Remote device’s name"), N_("NAME") },
Packit 8fb625
	{ "dest", 0, G_OPTION_FLAG_HIDDEN,
Packit 8fb625
			G_OPTION_ARG_STRING, &option_device, NULL, NULL },
Packit 8fb625
	{ G_OPTION_REMAINING, 0, 0,
Packit 8fb625
			G_OPTION_ARG_FILENAME_ARRAY, &option_files },
Packit 8fb625
	{ NULL },
Packit 8fb625
};
Packit 8fb625
Packit 8fb625
int main(int argc, char *argv[])
Packit 8fb625
{
Packit 8fb625
	GError *error = NULL;
Packit 8fb625
	int i;
Packit 8fb625
Packit 8fb625
	bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
Packit 8fb625
	bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
Packit 8fb625
	textdomain(GETTEXT_PACKAGE);
Packit 8fb625
Packit 8fb625
	error = NULL;
Packit 8fb625
Packit 8fb625
	if (gtk_init_with_args(&argc, &argv, _("[FILE…]"),
Packit 8fb625
				options, GETTEXT_PACKAGE, &error) == FALSE) {
Packit 8fb625
		if (error != NULL) {
Packit 8fb625
			g_printerr("%s\n", error->message);
Packit 8fb625
			g_error_free(error);
Packit 8fb625
		} else
Packit 8fb625
			g_printerr("An unknown error occurred\n");
Packit 8fb625
Packit 8fb625
		return 1;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	gtk_window_set_default_icon_name("bluetooth");
Packit 8fb625
Packit 8fb625
	cancellable = g_cancellable_new ();
Packit 8fb625
Packit 8fb625
	/* A device name, but no device? */
Packit 8fb625
	if (option_device == NULL && option_device_name != NULL) {
Packit 8fb625
		if (option_files != NULL)
Packit 8fb625
			g_strfreev(option_files);
Packit 8fb625
		g_free (option_device_name);
Packit 8fb625
		return 1;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	if (option_files == NULL) {
Packit 8fb625
		option_files = show_select_dialog();
Packit 8fb625
		if (option_files == NULL)
Packit 8fb625
			return 1;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	if (option_device == NULL) {
Packit 8fb625
		option_device = show_browse_dialog(&option_device_name);
Packit 8fb625
		if (option_device == NULL) {
Packit 8fb625
			g_strfreev(option_files);
Packit 8fb625
			return 1;
Packit 8fb625
		}
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	file_count = g_strv_length(option_files);
Packit 8fb625
Packit 8fb625
	for (i = 0; i < file_count; i++) {
Packit 8fb625
		gchar *filename;
Packit 8fb625
		struct stat st;
Packit 8fb625
Packit 8fb625
		filename = filename_to_path(option_files[i]);
Packit 8fb625
Packit 8fb625
		if (filename != NULL) {
Packit 8fb625
			g_free(option_files[i]);
Packit 8fb625
			option_files[i] = filename;
Packit 8fb625
		}
Packit 8fb625
Packit 8fb625
		if (g_file_test(option_files[i],
Packit 8fb625
					G_FILE_TEST_IS_REGULAR) == FALSE) {
Packit 8fb625
			option_files[i][0] = '\0';
Packit 8fb625
			continue;
Packit 8fb625
		}
Packit 8fb625
Packit 8fb625
		if (g_stat(option_files[i], &st) < 0)
Packit 8fb625
			option_files[i][0] = '\0';
Packit 8fb625
		else
Packit 8fb625
			total_size += st.st_size;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
Packit 8fb625
	if (conn == NULL) {
Packit 8fb625
		if (error != NULL) {
Packit 8fb625
			g_printerr("Connecting to session bus failed: %s\n",
Packit 8fb625
							error->message);
Packit 8fb625
			g_error_free(error);
Packit 8fb625
		} else
Packit 8fb625
			g_print("An unknown error occurred\n");
Packit 8fb625
Packit 8fb625
		return 1;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	client_proxy = g_dbus_proxy_new_sync (conn,
Packit 8fb625
					      G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
Packit 8fb625
					      NULL,
Packit 8fb625
					      OBEX_SERVICE,
Packit 8fb625
					      OBEX_PATH,
Packit 8fb625
					      CLIENT_IFACE,
Packit 8fb625
					      cancellable,
Packit 8fb625
					      &error);
Packit 8fb625
	if (client_proxy == NULL) {
Packit 8fb625
		g_printerr("Acquiring proxy failed: %s\n", error->message);
Packit 8fb625
		g_error_free (error);
Packit 8fb625
		return 1;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	if (option_device_name == NULL)
Packit 8fb625
		option_device_name = get_device_name(option_device);
Packit 8fb625
	if (option_device_name == NULL)
Packit 8fb625
		option_device_name = g_strdup(option_device);
Packit 8fb625
Packit 8fb625
	create_window();
Packit 8fb625
Packit 8fb625
	if (!g_cancellable_is_cancelled (cancellable))
Packit 8fb625
		send_files ();
Packit 8fb625
Packit 8fb625
	gtk_main();
Packit 8fb625
Packit 8fb625
	g_cancellable_cancel (cancellable);
Packit 8fb625
Packit 8fb625
	g_clear_object (&cancellable);
Packit 8fb625
	g_clear_object (&current_transfer);
Packit 8fb625
	g_clear_object (&session);
Packit 8fb625
	g_object_unref (client_proxy);
Packit 8fb625
	g_object_unref (conn);
Packit 8fb625
Packit 8fb625
	g_strfreev(option_files);
Packit 8fb625
	g_free(option_device);
Packit 8fb625
	g_free(option_device_name);
Packit 8fb625
Packit 8fb625
	return 0;
Packit 8fb625
}