All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bastien Nocera <hadess@hadess.net>
To: BlueZ development <bluez-devel@lists.sourceforge.net>
Subject: Re: [Bluez-devel] [PATCH] Updated sendto
Date: Wed, 27 Feb 2008 01:28:02 +0000	[thread overview]
Message-ID: <1204075682.2754.245.camel@cookie.hadess.net> (raw)
In-Reply-To: <1E808724-F721-415C-90F9-09C1B6E52C55@holtmann.org>

[-- Attachment #1: Type: text/plain, Size: 522 bytes --]


On Tue, 2008-02-26 at 02:21 +0100, Marcel Holtmann wrote:
<snip>
> lets use gtk_main_quit() since the exit code doesn't really matter and  
> show me an updated patch. I am still working through the whole thing.  
> We need some simplifications here and there, because the code looks  
> too complicated to me.

There's some bits of the code that aren't as easy to read as they could,
but it's hard to take a step back when you've used to the code.

Let me know which parts you don't like and we can rework them.

Cheers

[-- Attachment #2: bluez-gnome-new-sendto-10.patch --]
[-- Type: text/x-patch, Size: 30100 bytes --]

Index: sendto/dialog.h
===================================================================
RCS file: /cvsroot/bluez/gnome/sendto/dialog.h,v
retrieving revision 1.1
diff -u -p -r1.1 dialog.h
--- sendto/dialog.h	23 Feb 2008 06:20:17 -0000	1.1
+++ sendto/dialog.h	27 Feb 2008 01:25:10 -0000
@@ -21,5 +21,7 @@
  *
  */
 
+#include <glib.h>
+
 gchar *show_browse_dialog(void);
 GSList *show_select_dialog(void);
Index: sendto/main.c
===================================================================
RCS file: /cvsroot/bluez/gnome/sendto/main.c,v
retrieving revision 1.24
diff -u -p -r1.24 main.c
--- sendto/main.c	23 Feb 2008 06:20:17 -0000	1.24
+++ sendto/main.c	27 Feb 2008 01:25:10 -0000
@@ -3,6 +3,8 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2007 Tadas Dailyda <tadas@dailyda.com>
+ *  Copyright (C) 2007 Bastien Nocera <hadess@hadess.net>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -25,199 +27,618 @@
 #include <config.h>
 #endif
 
-#include <dbus/dbus-glib.h>
 
 #include <glib/gi18n.h>
+#include <gtk/gtk.h>
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <dbus/dbus-glib.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
 #include <gtk/gtk.h>
 
+#include "dbus-glue.h"
 #include "marshal.h"
-
 #include "dialog.h"
 
-static DBusGConnection *conn = NULL;
+#define MSEC_PER_SEC 1000000
 
-static GtkWidget *dialog;
-static GtkWidget *label_filename;
-static GtkWidget *label_status;
-static GtkWidget *progress;
-
-static guint64 filesize = 0;
+/* DBus */
+static DBusGConnection *connection = NULL;
+static DBusGProxy *manager_proxy = NULL;
+static DBusGProxy *session_proxy = NULL;
+/* GTK */
+static GtkWidget *main_dialog, *from_label, *operation_label, *progress_bar;
+/* sending related */
+static gsize file_length = 0;
+static guint file_count = 0;
+static guint current_file = 0;
+static GSList *file_list = NULL;
+static guint byte_count = 0;
+static guint bytes_sent = 0;
+static gint64 first_transfer_time = 0;
+static gint64 last_update_time = 0;
+
+typedef enum {
+	BUTTONS_OK,
+	BUTTONS_RETRY_CANCEL,
+	BUTTONS_RETRY_SKIP_CANCEL
+} ButtonSet;
+
+/* Command line options */
+static gchar **files_to_send = NULL;
+static gchar *bdaddrstr = NULL;
+static gchar *device_name = NULL;
+
+#define DIALOG_RESPONSE_SKIP 1
+#define DIALOG_RESPONSE_RETRY 2
+
+static void error_occurred_cb(DBusGProxy *proxy, const gchar *error_name,
+			      const gchar *error_message, gpointer user_data);
+
+static const GOptionEntry options[] = {
+	{"dest", 'd', 0, G_OPTION_ARG_STRING, &bdaddrstr, 
+		"Bluetooth address of destination device", "BDADDR"},
+	{G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &files_to_send},
+	{NULL}
+};
 
-static void response_callback(GtkWidget *dialog,
-					gint response, gpointer user_data)
+static gint64 get_system_time(void)
 {
-	gtk_widget_destroy(dialog);
+	struct timeval tmp;
 
-	gtk_main_quit();
+	gettimeofday(&tmp, NULL);
+	return (gint64)tmp.tv_usec + (gint64)tmp.tv_sec * G_GINT64_CONSTANT(1000000);
 }
 
-static void create_window(const gchar *filename)
+static gboolean is_palm_device(const gchar *bdaddr)
 {
-	GtkWidget *vbox;
-	GtkWidget *label;
-	gchar *text;
+	return (g_str_has_prefix(bdaddr, "00:04:6B")
+		|| g_str_has_prefix(bdaddr, "00:07:E0")
+		|| g_str_has_prefix(bdaddr, "00:0E:20"));
+}
 
-	dialog = gtk_dialog_new_with_buttons(_("File Transfer"), NULL,
-				GTK_DIALOG_NO_SEPARATOR,
-				GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
+/* Return the local absolute filename for the file, and its size
+ * if the file exists and is stat()'able */
+static gchar *normalise_filename(const gchar *filename, gint64 *size)
+{
+	char *ret;
+	struct stat file_stat;
 
-	gtk_window_set_default_size(GTK_WINDOW(dialog), 400, -1);
+	g_return_val_if_fail(filename != NULL, NULL);
+	g_return_val_if_fail(size != NULL, NULL);
 
-	gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
+	if (g_str_has_prefix(filename, "file://")) {
+		ret = g_filename_from_uri(filename, NULL, NULL);
+		if (ret == NULL)
+			return NULL;
+	} else if (filename[0] == '/') {
+		ret = g_strdup(filename);
+	} else {
+		gchar *curdir;
+
+		curdir = g_get_current_dir();
+		ret = g_build_filename(curdir, filename, NULL);
+		g_free(curdir);
+	}
 
-	vbox = gtk_vbox_new(FALSE, 6);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
-	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
+	if (!g_file_test(ret, G_FILE_TEST_IS_REGULAR)) {
+		g_free(ret);
+		return NULL;
+	}
 
-	label = gtk_label_new(NULL);
-	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
-	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+	if (!g_stat(ret, &file_stat)) {
+		*size = file_stat.st_size;
+	} else {
+		g_free(ret);
+		return NULL;
+	}
 
-	label_filename = label;
+	return ret;
+}
 
-	progress = gtk_progress_bar_new();
-	gtk_box_pack_start(GTK_BOX(vbox), progress, FALSE, FALSE, 0);
+static gchar *get_device_name(void)
+{
+	DBusGConnection *connection;
+	DBusGProxy *manager;
+	GError *error = NULL;
+	gchar *name, **adapters;
+	guint i;
 
-	label = gtk_label_new(NULL);
-	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
-	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
-	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 6);
+	name = NULL;
 
-	label_status = label;
+	connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL);
+	if (connection == NULL)
+		return NULL;
+
+	manager = dbus_g_proxy_new_for_name(connection, "org.bluez",
+					    "/org/bluez", "org.bluez.Manager");
+	if (!manager) {
+		dbus_g_connection_unref(connection);
+		return NULL;
+	}
 
-	text = g_strdup_printf("<b>%s</b>", filename);
-	gtk_label_set_markup(GTK_LABEL(label_filename), text);
-	g_free(text);
+	if (!manager_list_adapters(manager, &adapters, &error)) {
+		g_object_unref(manager);
+		dbus_g_connection_unref(connection);
+		return NULL;
+	}
 
-	gtk_label_set_markup(GTK_LABEL(label_status), _("Connecting..."));
+	for (i = 0; adapters[i] != NULL; i++) {
+		DBusGProxy *adapter;
 
-	gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog),
-						GTK_RESPONSE_CLOSE, FALSE);
+		adapter = dbus_g_proxy_new_for_name(connection, "org.bluez",
+						    adapters[i], "org.bluez.Adapter");
+		if (dbus_g_proxy_call(adapter, "GetRemoteName", NULL,
+				      G_TYPE_STRING, bdaddrstr, G_TYPE_INVALID,
+				      G_TYPE_STRING, &name, G_TYPE_INVALID)) {
+			if (name != NULL && name[0] != '\0') {
+				g_object_unref(adapter);
+				break;
+			}
+		}
+		g_object_unref(adapter);
+	}
 
-	g_signal_connect(G_OBJECT(dialog), "response",
-				G_CALLBACK(response_callback), NULL);
+	g_strfreev(adapters);
+	g_object_unref(manager);
+	dbus_g_connection_unref(connection);
 
-	gtk_widget_show_all(dialog);
+	return name;
 }
 
-static void transfer_started(DBusGProxy *proxy, gchar *a, gchar *b,
-					guint64 size, gpointer user_data)
+static gint show_error_dialog(GtkWindow *parent, ButtonSet buttons,
+			      const gchar *primary_text, const gchar *secondary_text)
 {
-	gchar *text;
+	GtkWidget *dialog;
+	gchar *primary_text_markup;
+	gint ret;
+
+	primary_text_markup = g_strdup_printf("<span weight=\"bold\" size=\"larger\">%s</span>", 
+					      primary_text);
+	dialog = gtk_message_dialog_new_with_markup(parent, 0, GTK_MESSAGE_ERROR, 
+						    buttons==BUTTONS_OK? GTK_BUTTONS_OK: GTK_BUTTONS_CANCEL, 
+						    primary_text_markup);
+	gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
+						 secondary_text);
+	if (buttons == BUTTONS_RETRY_SKIP_CANCEL) {
+		gtk_dialog_add_button(GTK_DIALOG(dialog), _("Skip"),
+				      DIALOG_RESPONSE_SKIP);
+	}
+	if (buttons != BUTTONS_OK) {
+		gtk_dialog_add_button(GTK_DIALOG(dialog), _("Retry"),
+				      DIALOG_RESPONSE_RETRY);
+	}
+	ret = gtk_dialog_run(GTK_DIALOG(dialog));
 
-	filesize = size;
+	gtk_widget_destroy(dialog);
+	g_free(primary_text_markup);
+	return ret;
+}
 
-	text = g_strdup_printf(_("Starting transfer of %jd bytes"), size);
-	gtk_label_set_markup(GTK_LABEL(label_status), text);
-	g_free(text);
+static gint show_connection_error_dialog(GtkWindow *parent, const gchar *bdaddr,
+					 const gchar *primary_text)
+{
+	if (!is_palm_device(bdaddrstr)) {
+		return show_error_dialog(parent,
+					 BUTTONS_RETRY_CANCEL,
+					 primary_text,
+					 _("Make sure that remote device is on and that it accepts Bluetooth connections."));
+	} else {
+		return show_error_dialog(parent,
+					 BUTTONS_RETRY_CANCEL,
+					 primary_text,
+					 _("Make sure \"Beam receive\" is enabled in the Power preferences, and Bluetooth is enabled, on your Palm device."));
+	}
+}
+
+static gint handle_file_sending_error(const gchar *error_text,
+				      const gchar *error_secondary_text)
+{
+	ButtonSet buttons;
+	gint response_id;
 
-	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), 0.0);
+	if (file_count > 1 && current_file < file_count - 1)
+		buttons = BUTTONS_RETRY_SKIP_CANCEL;
+	else
+		buttons = BUTTONS_RETRY_CANCEL;
+
+	response_id = show_error_dialog(GTK_WINDOW(main_dialog), buttons, 
+					error_text, error_secondary_text);
+
+	switch (response_id) {
+	case DIALOG_RESPONSE_SKIP:
+		current_file++;
+		bytes_sent += file_length;
+	case DIALOG_RESPONSE_RETRY:
+		return TRUE;
+	case GTK_RESPONSE_CANCEL:
+	default:
+		gtk_main_quit();
+		break;
+	}
+	return response_id;
 }
 
-static void transfer_progress(DBusGProxy *proxy,
-					guint64 bytes, gpointer user_data)
+static void cancel_clicked_cb(GtkWidget *button, gpointer user_data)
 {
+	gtk_main_quit();
+}
+
+static void ui_init(void)
+{
+	GtkWidget *vbox, *vbox_parent, *table;
+	GtkWidget *label1, *label2, *label3, *target_label;
+	GtkWidget *button;
 	gchar *text;
-	gdouble fraction;
 
-	text = g_strdup_printf(_("Transfered %jd of %jd bytes"),
-							bytes, filesize);
-	gtk_label_set_markup(GTK_LABEL(label_status), text);
+	device_name = get_device_name();
+
+	/* main dialog */
+	main_dialog = gtk_dialog_new();
+	gtk_dialog_set_has_separator(GTK_DIALOG(main_dialog), FALSE);
+	gtk_window_set_title(GTK_WINDOW(main_dialog),
+			     _("Bluetooth file transfer"));
+	gtk_window_set_icon_name(GTK_WINDOW(main_dialog), "stock_bluetooth");
+	gtk_window_set_type_hint(GTK_WINDOW(main_dialog),
+				 GDK_WINDOW_TYPE_HINT_NORMAL);
+	gtk_window_set_position(GTK_WINDOW(main_dialog), GTK_WIN_POS_CENTER);
+	gtk_window_set_resizable(GTK_WINDOW(main_dialog), FALSE);
+	gtk_widget_set(main_dialog, "width-request", 400, NULL);
+	button = gtk_dialog_add_button(GTK_DIALOG(main_dialog),
+				       GTK_STOCK_CANCEL,
+				       GTK_RESPONSE_CANCEL);
+	g_signal_connect(G_OBJECT(button), "clicked",
+			 G_CALLBACK(cancel_clicked_cb), NULL);
+	gtk_container_set_border_width(GTK_CONTAINER(main_dialog), 6);
+
+	/* table elements */
+	from_label = gtk_label_new(NULL);
+	gtk_misc_set_alignment(GTK_MISC(from_label), 0, 0.5);
+	gtk_label_set_ellipsize(GTK_LABEL(from_label), PANGO_ELLIPSIZE_MIDDLE);
+	target_label = gtk_label_new(NULL);
+	gtk_misc_set_alignment(GTK_MISC(target_label), 0, 0.5);
+	gtk_label_set_ellipsize(GTK_LABEL(target_label), PANGO_ELLIPSIZE_END);
+	gtk_label_set_text(GTK_LABEL(target_label), device_name ? device_name : bdaddrstr);
+	label2 = gtk_label_new(NULL);
+	text = g_markup_printf_escaped("<b>%s</b>", _("From:"));
+	gtk_label_set_markup(GTK_LABEL(label2), text);
+	g_free(text);
+	label3 = gtk_label_new(NULL);
+	gtk_misc_set_alignment(GTK_MISC(label3), 1, 0.5);
+	text = g_markup_printf_escaped("<b>%s</b>", _("To:"));
+	gtk_label_set_markup(GTK_LABEL(label3), text);
 	g_free(text);
 
-	fraction = (gdouble) bytes / (gdouble) filesize;
-	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction);
+	/* table */
+	table = gtk_table_new(2, 2, FALSE);
+	gtk_table_set_col_spacings(GTK_TABLE(table), 4);
+	gtk_table_set_row_spacings(GTK_TABLE(table), 4);
+	gtk_table_attach_defaults(GTK_TABLE(table), from_label, 1, 2, 0, 1);
+	gtk_table_attach_defaults(GTK_TABLE(table), target_label, 1, 2, 1, 2);
+	gtk_table_attach(GTK_TABLE(table), label2, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+	gtk_table_attach(GTK_TABLE(table), label3, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+
+	/* vbox elements */
+	label1 = gtk_label_new(NULL);
+	gtk_misc_set_alignment(GTK_MISC(label1), 0, 0.5);
+	text = g_markup_printf_escaped("<span weight=\"bold\" size=\"larger\">%s</span>",
+				       _("Sending files via bluetooth"));
+	gtk_label_set_markup(GTK_LABEL(label1), text);
+	g_free(text);
+	progress_bar = gtk_progress_bar_new();
+	gtk_progress_bar_set_ellipsize(GTK_PROGRESS_BAR(progress_bar),
+				       PANGO_ELLIPSIZE_END);
+	gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress_bar),
+				  _("Connecting..."));
+	operation_label = gtk_label_new(NULL);
+	gtk_misc_set_alignment(GTK_MISC(operation_label), 0, 0.5);
+	gtk_label_set_ellipsize(GTK_LABEL(operation_label), PANGO_ELLIPSIZE_END);
+
+	/* vbox */
+	vbox = gtk_vbox_new(FALSE, 0);
+	gtk_box_set_spacing(GTK_BOX(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_box_pack_start_defaults(GTK_BOX(vbox), label1);
+	gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 9);
+	gtk_box_pack_start_defaults(GTK_BOX(vbox), progress_bar);
+	gtk_box_pack_start(GTK_BOX(vbox), operation_label, TRUE, TRUE, 2);
+	vbox_parent = gtk_bin_get_child(GTK_BIN(main_dialog));
+	gtk_box_pack_start_defaults(GTK_BOX(vbox_parent), vbox);
+
+	gtk_widget_show_all(main_dialog);
 }
 
-static void transfer_completed(DBusGProxy *proxy, gpointer user_data)
+static gboolean send_one(gpointer user_data)
 {
-	gtk_label_set_markup(GTK_LABEL(label_status), _("Completed"));
+	const gchar *fname;
+	gint ret;
+	gchar *bname, *dirname;
+	GError *err = NULL;
+	gchar *operation_text, *operation_markup, *progressbar_text;
+
+	if ((fname = g_slist_nth_data(file_list, current_file))) {
+		/* there's a file to send */
+		dbus_g_proxy_call(session_proxy, "SendFile", &err,
+				  G_TYPE_STRING, fname, G_TYPE_INVALID, G_TYPE_INVALID);
+
+		if (err != NULL) {
+			ret = handle_file_sending_error(_("Unable to read file"),
+							err->message);
+			if (ret != GTK_RESPONSE_CANCEL) {
+				g_idle_add((GSourceFunc) send_one, NULL);
+			}
+			g_error_free(err);
+			return FALSE;
+		}
 
-	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), 1.0);
+		if (!first_transfer_time) {
+			first_transfer_time = get_system_time();
+		}
+		bname = g_path_get_basename(fname);
+		dirname = g_path_get_dirname(fname);
 
-	dbus_g_proxy_call(proxy, "Disconnect", NULL, G_TYPE_INVALID,
-							G_TYPE_INVALID);
+		operation_text = g_strdup_printf(_("Sending %s"), bname);
+		operation_markup = g_markup_printf_escaped("<i>%s</i>", operation_text);
+		progressbar_text = g_strdup_printf(_("Sending file: %d of %d"),
+						   current_file+1,
+						   file_count);
+		gtk_label_set_text(GTK_LABEL(from_label), dirname);
+		gtk_label_set_markup(GTK_LABEL(operation_label), operation_markup);
+		gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress_bar),
+					  progressbar_text);
+
+		g_free(bname);
+		g_free(dirname);
+		g_free(operation_text);
+		g_free(operation_markup);
+		g_free(progressbar_text);
+	} else {
+		/* nothing left to send, time to quit */
+		gtk_main_quit();
+	}
+	return FALSE;
+}
 
-	gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog),
-						GTK_RESPONSE_CLOSE, TRUE);
+static void session_connected_cb(DBusGProxy *proxy, gpointer user_data)
+{
+	/* OBEX connect has succeeded, so start sending */
+	g_idle_add((GSourceFunc) send_one, NULL);
 }
 
-static void session_connected(DBusGProxy *proxy, gpointer user_data)
+static void transfer_started_cb(DBusGProxy *proxy, const gchar *filename,
+				const gchar *local_path, guint64 byte_count, gpointer user_data)
 {
-	gchar *filename = user_data;
-	GError *error = NULL;
+	file_length = byte_count;
+}
 
-	gtk_label_set_markup(GTK_LABEL(label_status), _("Connected"));
+static void transfer_cancelled_cb(DBusGProxy *proxy, gpointer user_data)
+{
+	gint ret;
+	gchar *error_text;
 
-	dbus_g_proxy_call(proxy, "SendFile", &error,
-				G_TYPE_STRING, filename, G_TYPE_INVALID,
-							G_TYPE_INVALID);
-
-	if (error != NULL) {
-		g_printerr("Sending of file %s failed: %s\n", filename,
-							error->message);
-		g_error_free(error);
-		gtk_main_quit();
+	error_text = g_strdup_printf(_("An error occured while sending file '%s'"),
+				     (gchar *)g_slist_nth_data(file_list, current_file));
+	ret = handle_file_sending_error(error_text,
+					_("The remote device cancelled the transfer"));
+
+	if (ret != GTK_RESPONSE_CANCEL)
+		g_idle_add((GSourceFunc) send_one, NULL);
+
+	g_free(error_text);
+}
+
+static void transfer_progress_cb(DBusGProxy *proxy, guint64 bytes_transferred, gpointer user_data)
+{
+	gdouble frac;
+	guint actual_bytes_sent;
+	gint elapsed_time;
+	gint transfer_rate;
+	gint time_remaining;
+	gint64 current_time;
+	gchar *str, *str2;
+	gchar *progressbar_text;
+
+	/* update progress bar fraction */
+	actual_bytes_sent = bytes_sent + bytes_transferred;
+	frac = (gdouble)actual_bytes_sent / byte_count;
+	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar), frac);
+
+	/* update progress bar text (time remaining)
+	 * (only update 4 times in a second) */
+	current_time = get_system_time();
+	elapsed_time = (current_time - first_transfer_time) / MSEC_PER_SEC;
+
+	if (last_update_time) {
+		if (current_time < last_update_time + MSEC_PER_SEC / 4)
+			return;
+		else
+			last_update_time = current_time;
+	} else {
+		last_update_time = current_time;
 	}
+
+	if (!elapsed_time)
+		return;
+
+	transfer_rate = actual_bytes_sent / elapsed_time;
+	if (transfer_rate == 0)
+		return;
+
+	time_remaining = (byte_count - actual_bytes_sent) / transfer_rate;
+
+	if (time_remaining >= 3600) {
+		str = g_strdup_printf(_("(%d:%02d:%d Remaining)"), 
+				      time_remaining / 3600,
+				      (time_remaining % 3600) / 60,
+				      (time_remaining % 3600) % 60);
+	} else {
+		str = g_strdup_printf(_("(%d:%02d Remaining)"), 
+				      time_remaining / 60,
+				      time_remaining % 60);
+	}
+
+	/* Translators:
+	 * Sending file 1 of 3 */
+	str2 = g_strdup_printf(_("Sending file %d of %d"),
+			       current_file + 1,
+			       file_count);
+	progressbar_text = g_strconcat(str2, " ", str, NULL);
+	gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress_bar),
+				  progressbar_text);
+	g_free(str);
+	g_free(str2);
+	g_free(progressbar_text);
 }
 
-static void create_notify(DBusGProxy *proxy,
-				DBusGProxyCall *call, void *user_data)
+static void transfer_completed_cb(DBusGProxy *proxy, gpointer user_data)
+{
+	current_file++;
+	bytes_sent += file_length;
+
+	g_idle_add((GSourceFunc) send_one, NULL);
+}
+
+static void session_created_cb(DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
 {
 	GError *error = NULL;
 	const gchar *path = NULL;
 
-	if (dbus_g_proxy_end_call(proxy, call, &error,
-					DBUS_TYPE_G_OBJECT_PATH, &path,
-						G_TYPE_INVALID) == FALSE) {
-		gchar *text, *message;
-
-		if (error != NULL) {
-			message = g_strdup(error->message);
-			g_error_free(error);
-		} else
-			message = g_strdup(_("An unknown error occured"));
-
-		text = g_strdup_printf("<span foreground=\"red\">%s</span>",
-								message);
-		gtk_label_set_markup(GTK_LABEL(label_status), text);
-		g_free(text);
-
-		g_free(message);
+	if (!dbus_g_proxy_end_call(proxy, call, &error,
+				   DBUS_TYPE_G_OBJECT_PATH, &path, G_TYPE_INVALID)) {
+		const gchar *error_name = NULL;
+		gint response_id;
+
+		if (error && error->code == DBUS_GERROR_REMOTE_EXCEPTION)
+			error_name = dbus_g_error_get_name(error);
+		if (error_name && !strcmp(error_name, "org.openobex.Error.ConnectionAttemptFailed")) {
+			response_id = show_connection_error_dialog(GTK_WINDOW(main_dialog), bdaddrstr, error->message);
+			if (response_id == DIALOG_RESPONSE_RETRY) {
+				/* Try to create Session again */
+				dbus_g_proxy_begin_call(manager_proxy,
+							"CreateBluetoothSession",
+							(DBusGProxyCallNotify) session_created_cb, NULL, NULL,
+							G_TYPE_STRING, bdaddrstr, G_TYPE_STRING, "opp",
+							G_TYPE_BOOLEAN, FALSE, G_TYPE_INVALID);
+				goto out;
+			}
+		} else {
+			show_error_dialog(GTK_WINDOW(main_dialog), BUTTONS_OK,
+					  error->message, "");
+		}
 
-		gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog),
-						GTK_RESPONSE_CLOSE, TRUE);
-		return;
+		gtk_main_quit();
+		goto out;
 	}
 
-	proxy = dbus_g_proxy_new_for_name(conn, "org.openobex",
-						path, "org.openobex.Session");
+	session_proxy = dbus_g_proxy_new_for_name(connection,
+						       "org.openobex",
+						       path,
+						       "org.openobex.Session");
 
-	dbus_g_proxy_add_signal(proxy, "Connected", G_TYPE_INVALID);
+	dbus_g_proxy_add_signal(session_proxy, "Connected",
+				G_TYPE_INVALID);
+
+	dbus_g_proxy_connect_signal(session_proxy, "Connected",
+				    G_CALLBACK(session_connected_cb), NULL, NULL);
+
+	dbus_g_proxy_add_signal(session_proxy, "TransferStarted",
+				G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID);
+
+	dbus_g_proxy_connect_signal(session_proxy, "TransferStarted",
+				    G_CALLBACK(transfer_started_cb), NULL, NULL);
 
-	dbus_g_proxy_connect_signal(proxy, "Connected",
-				G_CALLBACK(session_connected), user_data, NULL);
+	dbus_g_proxy_add_signal(session_proxy, "Cancelled",
+				G_TYPE_INVALID);
+
+	dbus_g_proxy_connect_signal(session_proxy, "Cancelled",
+				    G_CALLBACK(transfer_cancelled_cb), NULL, NULL);
 
-	dbus_g_proxy_add_signal(proxy, "TransferStarted", G_TYPE_STRING,
-				G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID);
+	dbus_g_proxy_add_signal(session_proxy, "ErrorOccurred",
+				G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
 
-	dbus_g_proxy_connect_signal(proxy, "TransferStarted",
-				G_CALLBACK(transfer_started), NULL, NULL);
+	dbus_g_proxy_connect_signal(session_proxy, "ErrorOccurred",
+				    G_CALLBACK(error_occurred_cb), NULL, NULL);
 
-	dbus_g_proxy_add_signal(proxy, "TransferProgress",
-						G_TYPE_UINT64, G_TYPE_INVALID);
+	dbus_g_proxy_add_signal(session_proxy, "TransferProgress",
+				G_TYPE_UINT64, G_TYPE_INVALID);
 
-	dbus_g_proxy_connect_signal(proxy, "TransferProgress",
-				G_CALLBACK(transfer_progress), NULL, NULL);
+	dbus_g_proxy_connect_signal(session_proxy, "TransferProgress",
+				    G_CALLBACK(transfer_progress_cb), NULL, NULL);
+
+	dbus_g_proxy_add_signal(session_proxy, "TransferCompleted", 
+				G_TYPE_INVALID);
 
-	dbus_g_proxy_add_signal(proxy, "TransferCompleted", G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal(session_proxy, "TransferCompleted",
+				    G_CALLBACK(transfer_completed_cb), NULL, NULL);
 
-	dbus_g_proxy_connect_signal(proxy, "TransferCompleted",
-				G_CALLBACK(transfer_completed), NULL, NULL);
+	dbus_g_proxy_call(session_proxy, "Connect", &error, G_TYPE_INVALID,
+			  G_TYPE_INVALID);
 
-	dbus_g_proxy_call(proxy, "Connect", NULL, G_TYPE_INVALID,
-							G_TYPE_INVALID);
+out:
+	if (error)
+		g_error_free(error);
+}
+
+static void error_occurred_cb(DBusGProxy *proxy, const gchar *error_name, const gchar *error_message, gpointer user_data)
+{
+	gint ret;
+	gboolean link_error = FALSE;
+	gchar *error_text;
+	const gchar *reason;
+
+	g_message("ErrorOccurred");
+	g_message("Error name: %s", error_name);
+	g_message("Error message: %s", error_message);
+
+	error_text = g_strdup_printf(_("An error occured while sending file '%s'"),
+				     (gchar *)g_slist_nth_data(file_list, current_file));
+	if (!strcmp(error_name, "org.openobex.Error.LinkError")) {
+		g_object_unref(G_OBJECT(session_proxy));
+		reason = _("Connection to remote device was lost");
+		link_error = TRUE;
+	} else if (!strcmp(error_name, "org.openobex.Error.Forbidden")) {
+		reason = _("Remote device rejected file");
+	} else {
+		reason = _("Unknown error");
+	}
+	ret = handle_file_sending_error(error_text, reason);
+
+	if (ret != GTK_RESPONSE_CANCEL) {
+		if (link_error) {
+			/* Need to reestablish connection */
+			dbus_g_proxy_begin_call(manager_proxy, "CreateBluetoothSession",
+						(DBusGProxyCallNotify) session_created_cb, NULL, NULL,
+						G_TYPE_STRING, bdaddrstr, G_TYPE_STRING, "opp",
+						G_TYPE_INVALID);
+		} else {
+			g_idle_add((GSourceFunc) send_one, NULL);
+		}
+	}
+
+
+	g_free(error_text);
+}
+
+static void free_mem(void)
+{
+	if (files_to_send)
+		g_strfreev(files_to_send);
+	g_free(bdaddrstr);
+
+	if (main_dialog)
+		gtk_widget_destroy (main_dialog);
+	if (G_IS_OBJECT(manager_proxy))
+		g_object_unref(G_OBJECT(manager_proxy));
+	if (G_IS_OBJECT(session_proxy))
+		g_object_unref (G_OBJECT(session_proxy));
+	g_slist_free(file_list);
 }
 
 static void name_owner_changed(DBusGProxy *proxy, const char *name,
@@ -227,102 +648,121 @@ static void name_owner_changed(DBusGProx
 		gtk_main_quit();
 }
 
-static gchar *option_device = NULL;
-
-static GOptionEntry options[] = {
-	{ "device", 0, 0, G_OPTION_ARG_STRING, &option_device,
-				N_("Remote device to use"), "ADDRESS" },
-	{ NULL },
-};
-
 int main(int argc, char *argv[])
 {
-	DBusGProxy *proxy;
+	GOptionContext *option_context;
 	GError *error = NULL;
-	GSList *filenames;
-	gchar *filename, *address;
+	guint i;
 
 	bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
 	bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
 	textdomain(GETTEXT_PACKAGE);
 
-	error = NULL;
+	option_context = g_option_context_new("<file list>");
+	g_option_context_add_main_entries(option_context, options, GETTEXT_PACKAGE);
+	g_option_context_add_group(option_context, gtk_get_option_group(TRUE));
+	g_option_context_parse(option_context, &argc, &argv, &error);
+	g_option_context_free(option_context);
+	if (error) {
+		printf("Usage:\n");
+		printf("  %s [--dest=BDADDR] <file list>\n", g_get_prgname());
+		g_error_free(error);
+		free_mem();
+		return 0;
+	}
 
-	if (gtk_init_with_args(&argc, &argv, "[FILE...]",
-				options, GETTEXT_PACKAGE, &error) == FALSE) {
-		if (error != NULL) {
-			g_printerr("%s\n", error->message);
-			g_error_free(error);
-		} else
-			g_printerr("An unknown error occurred\n");
-
-		gtk_exit(1);
-	}
-
-	gtk_window_set_default_icon_name("bluetooth");
-
-	if (argc < 2) {
-		filenames = show_select_dialog();
-		if (filenames == NULL)
-			gtk_exit(1);
-	} else
-		filenames = g_slist_append(NULL, g_strdup(argv[1]));
-
-	if (option_device == NULL) {
-		address = show_browse_dialog();
-		if (address == NULL) {
-			g_slist_free(filenames);
-			gtk_exit(1);
-		}
-	} else
-		address = g_strdup(option_device);
+	gtk_init(&argc, &argv);
+
+	connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+	if (!connection) {
+		show_error_dialog(NULL, GTK_BUTTONS_OK,
+				  _("Please verify that D-Bus is correctly installed and setup."), error->message);
+		g_error_free(error);
+		return 1;
+	}
 
-	conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
-	if (conn == NULL) {
-		if (error != NULL) {
-			g_printerr("Connecting to session bus failed: %s\n",
-							error->message);
-			g_error_free(error);
-		} else
-			g_print("An unknown error occured\n");
+	main_dialog = NULL;
+	from_label = NULL;
+	operation_label = NULL;
+	progress_bar = NULL;
+
+	/* get a list of files to send from command-line */
+	if (files_to_send)
+		file_count = g_strv_length(files_to_send);
+	else
+		file_count = 0;
+	for (i = 0; i < file_count; i++) {
+		file_list = g_slist_append(file_list,
+						g_strdup(*(files_to_send + i)));
+	}
+	/* show file chooser if no files were specified */
+	if (!file_count) {
+		file_list = show_select_dialog();
+		file_count = g_slist_length(file_list);
+	}
+	/* Check if there are some files to send */
+	if (!file_count) {
+		free_mem();
+		return 0;
+	}
+	/* Check for non regular and non existand files and
+	 * determine total bytes to send */
+	for (i = 0; i < file_count; i++) {
+		GSList *item;
+		gchar *path, *filename;
+		gint64 size;
+
+		item = g_slist_nth(file_list, i);
+		path = (gchar *) item->data;
+		filename = normalise_filename(path, &size);
+		if (filename == NULL) {
+			g_free(path);
+			file_list = g_slist_remove_link(file_list, item);
+			continue;
+		}
+		g_free(item->data);
+		item->data = filename;
+		byte_count += size;
+	}
 
-		gtk_exit(1);
+	/* determine Bluetooth device to send to */
+	if (!bdaddrstr) {
+		bdaddrstr = show_browse_dialog();
+		if (!bdaddrstr) {
+			free_mem();
+			return 0;
+		}
 	}
 
 	dbus_g_object_register_marshaller(marshal_VOID__STRING_STRING_UINT64,
-				G_TYPE_NONE, G_TYPE_STRING,
-				G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID);
-
+					  G_TYPE_NONE, G_TYPE_STRING,
+					  G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID);
+	dbus_g_object_register_marshaller(marshal_VOID__STRING_STRING,
+					  G_TYPE_NONE, G_TYPE_STRING,
+					  G_TYPE_STRING, G_TYPE_INVALID);
 	dbus_g_object_register_marshaller(marshal_VOID__UINT64,
 				G_TYPE_NONE, G_TYPE_UINT64, G_TYPE_INVALID);
 
-	filename = g_slist_nth_data(filenames, 0);
-
-	create_window(filename);
+	ui_init();
 
-	proxy = dbus_g_proxy_new_for_name(conn, "org.openobex",
-				"/org/openobex", "org.openobex.Manager");
-
-	dbus_g_proxy_add_signal(proxy, "NameOwnerChanged",
-		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
-
-	dbus_g_proxy_connect_signal(proxy, "NameOwnerChanged",
-				G_CALLBACK(name_owner_changed), NULL, NULL);
-
-	dbus_g_proxy_begin_call(proxy, "CreateBluetoothSession",
-				create_notify, filename, NULL,
-				G_TYPE_STRING, address, G_TYPE_STRING, "opp",
+	manager_proxy = dbus_g_proxy_new_for_name(connection,
+						       "org.openobex",
+						       "/org/openobex",
+						       "org.openobex.Manager");
+	dbus_g_proxy_add_signal(manager_proxy, "NameOwnerChanged",
+				G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal(manager_proxy, "NameOwnerChanged",
+				    G_CALLBACK(name_owner_changed), NULL, NULL);
+
+	dbus_g_proxy_begin_call(manager_proxy, "CreateBluetoothSession",
+				(DBusGProxyCallNotify) session_created_cb, NULL, NULL,
+				G_TYPE_STRING, bdaddrstr, G_TYPE_STRING, "opp",
 				G_TYPE_INVALID);
 
 	gtk_main();
 
-	g_object_unref(proxy);
-
-	dbus_g_connection_unref(conn);
-
-	g_free(address);
-
-	g_slist_free(filenames);
+	free_mem();
 
 	return 0;
 }
+

[-- Attachment #3: Type: text/plain, Size: 228 bytes --]

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

[-- Attachment #4: Type: text/plain, Size: 164 bytes --]

_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel

      reply	other threads:[~2008-02-27  1:28 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-01-17 10:43 [Bluez-devel] [PATCH] Allow multiple files to be sent Bastien Nocera
2008-01-18 13:43 ` Bastien Nocera
2008-02-01 13:14   ` Bastien Nocera
2008-02-01 16:08     ` Bastien Nocera
2008-02-01 16:20       ` Bastien Nocera
2008-02-06 12:18         ` [Bluez-devel] [PATCH] Updated sendto Bastien Nocera
2008-02-06 13:08           ` Bastien Nocera
2008-02-07  0:59             ` Bastien Nocera
2008-02-23  1:30               ` Bastien Nocera
2008-02-24 18:29                 ` Bastien Nocera
2008-02-25  2:21                   ` Marcel Holtmann
2008-02-25 10:56                     ` Bastien Nocera
2008-02-25 20:36                       ` Marcel Holtmann
2008-02-26  1:18                         ` Bastien Nocera
2008-02-26  1:21                           ` Marcel Holtmann
2008-02-27  1:28                             ` Bastien Nocera [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1204075682.2754.245.camel@cookie.hadess.net \
    --to=hadess@hadess.net \
    --cc=bluez-devel@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.