File nautilus-177861-copy-remote-files.diff of Package nautilus

Patch by Joe Shaw <joeshaw@novell.com>

Some .desktop launchers specify that the launched application can only
open local files ("/home/foo/document.txt"), and not remote URIs
("smb://server/share/dir/document.txt").  This makes Nautilus download
those URIs before invoking an application which only supports local
files.

Fixes https://bugzilla.novell.com/show_bug.cgi?id=177861

Index: libnautilus-private/nautilus-mime-actions.c
===================================================================
--- libnautilus-private/nautilus-mime-actions.c.orig
+++ libnautilus-private/nautilus-mime-actions.c
@@ -108,17 +108,15 @@ GnomeVFSMimeApplication *
 nautilus_mime_get_default_application_for_file (NautilusFile *file)
 {
 	GnomeVFSMimeApplication *app;
-	char *uri, *mime_type;
+	char *mime_type;
 
 	if (!nautilus_mime_actions_check_if_open_with_attributes_ready (file)) {
 		return NULL;
 	}
 	
-	uri = nautilus_file_get_uri (file);
 	mime_type = nautilus_file_get_mime_type (file);
-	app = gnome_vfs_mime_get_default_application_for_uri (uri, mime_type);
+	app = gnome_vfs_mime_get_default_application (mime_type);
 	
-	g_free (uri);
 	g_free (mime_type);
 	
 	return app;
@@ -142,14 +140,13 @@ static GList *
 get_open_with_mime_applications (NautilusFile *file)
 {
 	char *guessed_mime_type;
-	char *mime_type, *uri;
+	char *mime_type;
 	GList *result;
 
 	guessed_mime_type = nautilus_file_get_guessed_mime_type (file);
 	mime_type = nautilus_file_get_mime_type (file);
-	uri = nautilus_file_get_uri (file);
 
-	result = gnome_vfs_mime_get_all_applications_for_uri (uri, mime_type);
+	result = gnome_vfs_mime_get_all_applications (mime_type);
 	result = g_list_sort (result, (GCompareFunc) application_compare_by_name);
 
 	if (strcmp (guessed_mime_type, mime_type) != 0) {
@@ -168,7 +165,6 @@ get_open_with_mime_applications (Nautilu
 	}
 
 	g_free (mime_type);
-	g_free (uri);
 	g_free (guessed_mime_type);
 	
 	return result;
@@ -212,13 +208,12 @@ gboolean
 nautilus_mime_has_any_applications_for_file (NautilusFile *file)
 {
 	GList *apps;
-	char *uri, *mime_type;
+	char *mime_type;
 	gboolean result;
 
-	uri = nautilus_file_get_uri (file);
 	mime_type = nautilus_file_get_mime_type (file);
 	
-	apps = gnome_vfs_mime_get_all_applications_for_uri (uri, mime_type);
+	apps = gnome_vfs_mime_get_all_applications (mime_type);
 	apps = filter_nautilus_handler (apps);
 		
 	if (apps) {
@@ -229,7 +224,6 @@ nautilus_mime_has_any_applications_for_f
 	}
 	
 	g_free (mime_type);
-	g_free (uri);
 
 	return result;
 }
Index: libnautilus-private/nautilus-program-choosing.c
===================================================================
--- libnautilus-private/nautilus-program-choosing.c.orig
+++ libnautilus-private/nautilus-program-choosing.c
@@ -29,6 +29,7 @@
 #include "nautilus-mime-actions.h"
 #include "nautilus-global-preferences.h"
 #include "nautilus-icon-factory.h"
+#include "nautilus-file-operations-progress.h"
 #include <eel/eel-glib-extensions.h>
 #include <eel/eel-gnome-extensions.h>
 #include <eel/eel-vfs-extensions.h>
@@ -416,24 +417,16 @@ slowly_and_stupidly_obtain_timestamp (Di
 
 
 
-
-
-/**
- * nautilus_launch_show_file:
- *
- * Shows a file using gnome_url_show.
- *
- * @file: the file whose uri will be shown.
- * @parent_window: window to use as parent for error dialog.
- */
-void nautilus_launch_show_file (NautilusFile *file,
-                                GtkWindow    *parent_window)
+static void
+launch_show_file (NautilusFile            *file,
+		  const char              *uri,
+		  GnomeVFSMimeApplication *application,
+		  GtkWindow               *parent_window)
 {
 	GnomeVFSResult result;
-	GnomeVFSMimeApplication *application;
 	GdkScreen *screen;
 	char **envp;
-	char *uri, *uri_scheme;
+	char *uri_scheme;
 	char *error_message, *detail_message;
         char *full_uri_for_display;
         char *uri_for_display;
@@ -446,19 +439,6 @@ void nautilus_launch_show_file (Nautilus
 	startup_notify = FALSE;
 #endif
 
-	g_return_if_fail (!nautilus_file_needs_slow_mime_type (file));
-
-	uri = NULL;
-	if (nautilus_file_is_nautilus_link (file)) {
-		uri = nautilus_file_get_activation_uri (file);
-	}
-	
-	if (uri == NULL) {
-		uri = nautilus_file_get_uri (file);
-	}
-		
-	application = nautilus_mime_get_default_application_for_file (file);
-	
 	screen = gtk_window_get_screen (parent_window);
 	envp = my_gdk_spawn_make_environment_for_screen (screen, NULL);
 	
@@ -650,31 +630,16 @@ void nautilus_launch_show_file (Nautilus
 	}
 	
 	g_free (uri_for_display);
-	
-	if (application != NULL) 
-		gnome_vfs_mime_application_free (application);
-
 	g_strfreev (envp);
-	g_free (uri);
 }
 
-/**
- * nautilus_launch_application:
- * 
- * Fork off a process to launch an application with a given file as a
- * parameter. Provide a parent window for error dialogs. 
- * 
- * @application: The application to be launched.
- * @file: The file whose location should be passed as a parameter to the application
- * @parent_window: A window to use as the parent for any error dialogs.
- */
-void
-nautilus_launch_application (GnomeVFSMimeApplication *application, 
-			     NautilusFile *file,
-			     GtkWindow *parent_window)
+static void
+launch_application (NautilusFile            *file,
+		    const char              *uri,
+		    GnomeVFSMimeApplication *application,
+		    GtkWindow               *parent_window)
 {
 	GdkScreen       *screen;
-	char		*uri;
 	char            *uri_scheme;
 	GList            uris;
 	char           **envp;
@@ -684,18 +649,9 @@ nautilus_launch_application (GnomeVFSMim
 	SnDisplay *sn_display;
 #endif
 
-	uri = NULL;
-	if (nautilus_file_is_nautilus_link (file)) {
-		uri = nautilus_file_get_activation_uri (file);
-	}
-	
-	if (uri == NULL) {
-		uri = nautilus_file_get_uri (file);
-	}
-
 	uris.next = NULL;
 	uris.prev = NULL;
-	uris.data = uri;
+	uris.data = (gpointer) uri;
 	
 	screen = gtk_window_get_screen (parent_window);
 	envp = my_gdk_spawn_make_environment_for_screen (screen, NULL);
@@ -802,10 +758,350 @@ nautilus_launch_application (GnomeVFSMim
 		break;
 	}
 	
-	g_free (uri);
 	g_strfreev (envp);
 }
 
+typedef void (*LaunchFunc) (NautilusFile            *file,
+			    const char              *uri,
+			    GnomeVFSMimeApplication *application,
+			    GtkWindow               *parent_window);
+
+typedef struct {
+	LaunchFunc launch_func;
+
+	NautilusFile *file;
+	GnomeVFSURI *src_uri;
+	char *tmp_uri;
+	GnomeVFSMimeApplication *application;
+	NautilusFileOperationsProgress *progress_dialog;
+	GtkWindow *parent_window;
+	GnomeVFSAsyncHandle *handle;
+
+	gboolean set_file;
+} DownloadInfo;
+
+static void
+free_download_info (DownloadInfo *info)
+{
+	nautilus_file_unref (info->file);
+	gnome_vfs_uri_unref (info->src_uri);
+	g_free (info->tmp_uri);
+	gnome_vfs_mime_application_free (info->application);
+	g_object_unref (info->parent_window);
+	if (info->progress_dialog != NULL)
+		gtk_widget_destroy (GTK_WIDGET (info->progress_dialog));
+	g_free (info);
+}
+
+static int
+progress_update_callback (GnomeVFSAsyncHandle      *handle,
+			  GnomeVFSXferProgressInfo *progress_info,
+			  gpointer                  user_data)
+{
+	DownloadInfo *download_info = user_data;
+
+	if (progress_info->bytes_total > 0) {
+		nautilus_file_operations_progress_set_total (download_info->progress_dialog,
+							     1, progress_info->bytes_total);
+
+		if (!download_info->set_file) {
+			char *short_name, *src_path, *from_text;
+
+			short_name = gnome_vfs_uri_extract_short_name (download_info->src_uri);
+			src_path = gnome_vfs_uri_extract_dirname (download_info->src_uri);
+
+			from_text = g_strdup_printf (_("%s on %s"), src_path,
+						     gnome_vfs_uri_get_host_name (download_info->src_uri));
+
+			nautilus_file_operations_progress_new_file (download_info->progress_dialog,
+							    _("Copying"),
+							    short_name,
+							    from_text,
+							    "",
+							    _("From"),
+							    "",
+							    1,
+							    progress_info->bytes_copied);
+
+			g_free (short_name);
+			g_free (src_path);
+			g_free (from_text);
+
+			download_info->set_file = TRUE;
+		}
+	}
+
+	nautilus_file_operations_progress_update_sizes (download_info->progress_dialog,
+							progress_info->bytes_copied,
+							progress_info->bytes_copied);
+
+	if (progress_info->phase == GNOME_VFS_XFER_PHASE_COMPLETED) {
+		nautilus_file_operations_progress_done (download_info->progress_dialog);
+		download_info->progress_dialog = NULL;
+
+		if (progress_info->vfs_status != GNOME_VFS_OK) {
+			eel_show_error_dialog (_("Can't Connect to Server"),
+					       gnome_vfs_result_to_string (progress_info->vfs_status),
+					       _("Can't Display Location"),
+					       GTK_WINDOW (download_info->parent_window));
+		} else {
+			/*
+			 * Mark the file as read-only to help let the user
+			 * know that this is a temporary file, not the
+			 * real thing.
+			 */
+			chmod (download_info->tmp_uri + 7, 0400);
+
+			download_info->launch_func (download_info->file,
+						    download_info->tmp_uri,
+						    download_info->application, 
+						    download_info->parent_window);
+		}
+
+		free_download_info (download_info);
+	}
+
+	return 1;
+}
+
+static void
+handle_response_callback (GtkDialog *dialog, int response, gpointer user_data)
+{
+	DownloadInfo *info = user_data;
+
+	gnome_vfs_async_cancel (info->handle);
+	nautilus_file_operations_progress_done (info->progress_dialog);
+	info->progress_dialog = NULL;
+	free_download_info (info);
+}
+
+static void
+handle_close_callback (GtkDialog *dialog, gpointer user_data)
+{
+	DownloadInfo *info = user_data;
+
+	gnome_vfs_async_cancel (info->handle);
+	nautilus_file_operations_progress_done (info->progress_dialog);
+	info->progress_dialog = NULL;
+	free_download_info (info);
+}
+
+static GnomeVFSResult
+copy_file_locally (NautilusFile            *file,
+		   const char              *uri,
+		   GnomeVFSMimeApplication *application,
+		   GtkWindow               *parent_window,
+		   LaunchFunc               launch_func)
+{
+	char *tmp_dir, *tmptmp;
+	char *tmp_uri;
+	GnomeVFSURI *src, *dest;
+	GList *src_list, *dest_list;
+	DownloadInfo *info;
+	GnomeVFSResult result;
+
+	/*
+	 * FIXME: Sigh, we have no way of cleaning this temporary
+	 * directory up.  We don't know the pid of the program started,
+	 * so we can't track its lifecycle and clean up after it's
+	 * closed.
+	 */
+	tmp_dir = g_build_path (G_DIR_SEPARATOR_S, g_get_tmp_dir (), "nautilus-XXXXXX", NULL);
+	tmptmp = mkdtemp (tmp_dir);
+	result = gnome_vfs_result_from_errno ();
+
+	if (tmptmp == NULL) {
+		char *full_display_uri, *display_uri;
+		char *error_message;
+
+		g_free (tmp_dir);
+
+		full_display_uri = eel_format_uri_for_display (uri);
+		display_uri = eel_str_middle_truncate (full_display_uri,
+						       MAX_URI_IN_DIALOG_LENGTH);
+		g_free (full_display_uri);
+
+		error_message = g_strdup_printf (_("Couldn't display \"%s\"."),
+						 display_uri);
+		eel_show_error_dialog (error_message,
+				       _("There was an error launching the application."),
+				       _("Can't Display Location"), parent_window);
+		g_free (error_message);
+
+		return result;
+	}
+
+	tmp_uri = g_strconcat ("file://", tmp_dir, G_DIR_SEPARATOR_S, g_basename (uri), NULL);
+	g_free (tmp_dir);
+
+	src = gnome_vfs_uri_new (uri);
+	dest = gnome_vfs_uri_new (tmp_uri);
+
+	src_list = g_list_append (NULL, src);
+	dest_list = g_list_append (NULL, dest);
+
+	info = g_new0 (DownloadInfo, 1);
+	info->launch_func = launch_func;
+	info->file = nautilus_file_ref (file);
+	info->src_uri = gnome_vfs_uri_ref (src);
+	info->tmp_uri = tmp_uri;
+	/* Sucky strings, but we're in a string freeze */
+	info->progress_dialog = nautilus_file_operations_progress_new (_("Copying files"),
+								       _("Copying files"),
+								       _("From:"),
+								       "", 1, 0, TRUE);
+	info->application = gnome_vfs_mime_application_copy (application);
+	info->parent_window = g_object_ref (parent_window);
+
+	gtk_window_set_transient_for (GTK_WINDOW (info->progress_dialog),
+				      parent_window);
+
+	g_signal_connect (info->progress_dialog,
+			  "response",
+			  G_CALLBACK (handle_response_callback),
+			  info);
+	g_signal_connect (info->progress_dialog,
+			  "close",
+			  G_CALLBACK (handle_close_callback),
+			  info);
+
+	result = gnome_vfs_async_xfer (&info->handle,
+				       src_list,
+				       dest_list,
+				       GNOME_VFS_XFER_DEFAULT,
+				       GNOME_VFS_XFER_ERROR_MODE_ABORT,
+				       GNOME_VFS_XFER_OVERWRITE_MODE_ABORT,
+				       GNOME_VFS_PRIORITY_DEFAULT,
+				       progress_update_callback, info,
+				       NULL, NULL);
+
+	g_list_free (src_list);
+	g_list_free (dest_list);
+	gnome_vfs_uri_unref (src);
+	gnome_vfs_uri_unref (dest);
+
+	return result;
+}
+
+/**
+ * nautilus_launch_show_file:
+ *
+ * Shows a file using gnome_url_show.
+ *
+ * @file: the file whose uri will be shown.
+ * @parent_window: window to use as parent for error dialog.
+ */
+void 
+nautilus_launch_show_file (NautilusFile *file,
+			   GtkWindow    *parent_window)
+{
+	char *uri;
+	GnomeVFSMimeApplication *application;
+
+	g_return_if_fail (!nautilus_file_needs_slow_mime_type (file));
+
+	uri = NULL;
+	if (nautilus_file_is_nautilus_link (file)) {
+		uri = nautilus_file_get_activation_uri (file);
+	}
+
+	if (uri == NULL) {
+		uri = nautilus_file_get_uri (file);
+	}
+
+	application = nautilus_mime_get_default_application_for_file (file);
+
+	if (g_ascii_strncasecmp (uri, "file://", 7) != 0
+	    && application != NULL
+	    && !gnome_vfs_mime_application_supports_uris (application)) {
+
+		GnomeVFSResult result;
+
+		result = copy_file_locally (file, uri, application, parent_window, launch_show_file);
+
+		if (result != GNOME_VFS_OK) {
+			char *full_display_uri, *display_uri;
+			char *error_message;
+
+			full_display_uri = eel_format_uri_for_display (uri);
+			display_uri = eel_str_middle_truncate (full_display_uri,
+							       MAX_URI_IN_DIALOG_LENGTH);
+			g_free (full_display_uri);
+
+			error_message = g_strdup_printf (_("Couldn't display \"%s\"."),
+							 display_uri);
+			eel_show_error_dialog (error_message,
+					       _("There was an error launching the application."),
+					       _("Can't Display Location"), parent_window);
+			g_free (error_message);
+		}
+	} else {
+		launch_show_file (file, uri, application, parent_window);
+	}
+
+	if (application != NULL) {
+		gnome_vfs_mime_application_free (application);
+	}
+
+	g_free (uri);
+}
+
+/**
+ * nautilus_launch_application:
+ * 
+ * Fork off a process to launch an application with a given file as a
+ * parameter. Provide a parent window for error dialogs. 
+ * 
+ * @application: The application to be launched.
+ * @file: The file whose location should be passed as a parameter to the application
+ * @parent_window: A window to use as the parent for any error dialogs.
+ */
+void
+nautilus_launch_application (GnomeVFSMimeApplication *application, 
+			     NautilusFile *file,
+			     GtkWindow *parent_window)
+{
+	char *uri;
+
+	uri = NULL;
+	if (nautilus_file_is_nautilus_link (file)) {
+		uri = nautilus_file_get_activation_uri (file);
+	}
+	
+	if (uri == NULL) {
+		uri = nautilus_file_get_uri (file);
+	}
+
+	if (!g_ascii_strncasecmp (uri, "file://", 7) != 0
+	    && !gnome_vfs_mime_application_supports_uris (application)) {
+
+		GnomeVFSResult result;
+
+		result = copy_file_locally (file, uri, application, parent_window, launch_application);
+
+		if (result != GNOME_VFS_OK) {
+			char *full_display_uri, *display_uri;
+			char *error_message;
+
+			full_display_uri = eel_format_uri_for_display (uri);
+			display_uri = eel_str_middle_truncate (full_display_uri,
+							       MAX_URI_IN_DIALOG_LENGTH);
+			g_free (full_display_uri);
+
+			error_message = g_strdup_printf (_("Couldn't display \"%s\"."),
+							 display_uri);
+			eel_show_error_dialog (error_message,
+					       _("There was an error launching the application."),
+					       _("Can't Display Location"), parent_window);
+			g_free (error_message);
+		}
+	} else {
+		launch_application (file, uri, application, parent_window);
+	}
+
+	g_free (uri);
+}
+
 /**
  * nautilus_launch_application_from_command:
  * 
openSUSE Build Service is sponsored by