rendered paste bodydiff --git a/client/gdaemonfile.c b/client/gdaemonfile.cindex 9e055c2..8a1ae74 100644--- a/client/gdaemonfile.c+++ b/client/gdaemonfile.c@@ -1939,50 +1939,71 @@ progress_callback_message (DBusConnection *connection, return DBUS_HANDLER_RESULT_HANDLED; } + static gboolean g_daemon_file_copy (GFile *source,- GFile *destination,- GFileCopyFlags flags,- GCancellable *cancellable,- GFileProgressCallback progress_callback,- gpointer progress_callback_data,- GError **error)+ GFile *destination,+ GFileCopyFlags flags,+ GCancellable *cancellable,+ GFileProgressCallback progress_callback,+ gpointer progress_callback_data,+ GError **error) {- GDaemonFile *daemon_source; DBusMessage *reply; char *local_path; char *obj_path, *dbus_obj_path; dbus_uint32_t flags_dbus; struct ProgressCallbackData data;+ gboolean source_is_daemon;+ gboolean dest_is_daemon;+ gboolean can_copy;+ gboolean can_upload;+ gboolean can_download; - if (!G_IS_DAEMON_FILE (destination))- {- /* Fall back to default move */- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Move not supported");- return FALSE;- }+ local_path = NULL;+ can_copy = can_upload = can_download = FALSE;+ source_is_daemon = G_IS_DAEMON_FILE (source);+ dest_is_daemon = G_IS_DAEMON_FILE (destination); - if (G_IS_DAEMON_FILE (source))+ if (source_is_daemon && dest_is_daemon) {- daemon_source = G_DAEMON_FILE (source);- local_path = NULL;+ can_copy = TRUE; }- else+ else if (dest_is_daemon && !source_is_daemon) {- daemon_source = NULL; local_path = g_file_get_path (source); - if (local_path == NULL)- {- /* This will cause the fallback code to be involved */- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,- _("Operation not supported, files on different mounts"));- return FALSE;- }+ if (local_path)+ can_upload = TRUE; }- - if (progress_callback)+ else if (source_is_daemon && !dest_is_daemon)+ {+ local_path = g_file_get_path (destination);++ if (local_path)+ can_download = TRUE;+ }+ else {+ /* This will cause the fallback code to be involved */+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,+ "Copy not supported");+ return FALSE;+ }+++ if (can_copy == FALSE && local_path == NULL)+ {+ /* This will cause the fallback code to be involved */+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,+ _("Operation not supported, files on different mounts"));+ return FALSE;++ }+++ if (progress_callback)+ { obj_path = g_strdup_printf ("/org/gtk/vfs/callback/%p", &obj_path); dbus_obj_path = obj_path; }@@ -1998,29 +2019,40 @@ g_daemon_file_copy (GFile *source, flags_dbus = flags; - if (daemon_source)+ if (can_copy) { reply = do_sync_2_path_call (source, destination, - G_VFS_DBUS_MOUNT_OP_COPY,- obj_path, progress_callback_message, &data,- NULL, cancellable, error,- DBUS_TYPE_UINT32, &flags_dbus,- DBUS_TYPE_OBJECT_PATH, &dbus_obj_path,- 0);+ G_VFS_DBUS_MOUNT_OP_COPY,+ obj_path, progress_callback_message, &data,+ NULL, cancellable, error,+ DBUS_TYPE_UINT32, &flags_dbus,+ DBUS_TYPE_OBJECT_PATH, &dbus_obj_path,+ 0); }- else+ else if (can_upload) { reply = do_sync_2_path_call (destination, NULL, - G_VFS_DBUS_MOUNT_OP_UPLOAD,- obj_path, progress_callback_message, &data,- NULL, cancellable, error,- G_DBUS_TYPE_CSTRING, &local_path,- DBUS_TYPE_UINT32, &flags_dbus,- DBUS_TYPE_OBJECT_PATH, &dbus_obj_path,- 0);- g_free (local_path);- }-+ G_VFS_DBUS_MOUNT_OP_UPLOAD,+ obj_path, progress_callback_message, &data,+ NULL, cancellable, error,+ G_DBUS_TYPE_CSTRING, &local_path,+ DBUS_TYPE_UINT32, &flags_dbus,+ DBUS_TYPE_OBJECT_PATH, &dbus_obj_path,+ 0);+ }+ else if (can_download)+ {+ reply = do_sync_2_path_call (source, NULL,+ G_VFS_DBUS_MOUNT_OP_DOWNLOAD,+ obj_path, progress_callback_message, &data,+ NULL, cancellable, error, + G_DBUS_TYPE_CSTRING, &local_path,+ DBUS_TYPE_UINT32, &flags_dbus,+ DBUS_TYPE_OBJECT_PATH, &dbus_obj_path,+ 0);+ }++ g_free (local_path); g_free (obj_path); if (reply == NULL)diff --git a/common/gvfsdaemonprotocol.h b/common/gvfsdaemonprotocol.hindex aa41f98..26d0622 100644--- a/common/gvfsdaemonprotocol.h+++ b/common/gvfsdaemonprotocol.h@@ -43,6 +43,7 @@ G_BEGIN_DECLS #define G_VFS_DBUS_MOUNT_OP_MAKE_SYMBOLIC_LINK "MakeSymbolicLink" #define G_VFS_DBUS_MOUNT_OP_COPY "Copy" #define G_VFS_DBUS_MOUNT_OP_UPLOAD "Upload"+#define G_VFS_DBUS_MOUNT_OP_DOWNLOAD "Download" #define G_VFS_DBUS_MOUNT_OP_MOVE "Move" #define G_VFS_DBUS_MOUNT_OP_SET_ATTRIBUTE "SetAttribute" #define G_VFS_DBUS_MOUNT_OP_QUERY_SETTABLE_ATTRIBUTES "QuerySettableAttributes"diff --git a/daemon/Makefile.am b/daemon/Makefile.amindex 9a5be5b..8681a69 100644--- a/daemon/Makefile.am+++ b/daemon/Makefile.am@@ -135,6 +135,7 @@ libdaemon_la_SOURCES = \ gvfsjobdelete.c gvfsjobdelete.h \ gvfsjobcopy.c gvfsjobcopy.h \ gvfsjobupload.c gvfsjobupload.h \+ gvfsjobdownload.c gvfsjobdownload.h \ gvfsjobmove.c gvfsjobmove.h \ gvfsjobmakedirectory.c gvfsjobmakedirectory.h \ gvfsjobmakesymlink.c gvfsjobmakesymlink.h \diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.cindex ddce08c..205661b 100644--- a/daemon/gvfsbackend.c+++ b/daemon/gvfsbackend.c@@ -49,6 +49,7 @@ #include <gvfsjobmakesymlink.h> #include <gvfsjobcreatemonitor.h> #include <gvfsjobupload.h>+#include <gvfsjobdownload.h> #include <gvfsjobcopy.h> #include <gvfsjobmove.h> #include <gvfsjobsetattribute.h>@@ -538,6 +539,10 @@ backend_dbus_handler (DBusConnection *connection, job = g_vfs_job_upload_new (connection, message, backend); else if (dbus_message_is_method_call (message, G_VFS_DBUS_MOUNT_INTERFACE,+ G_VFS_DBUS_MOUNT_OP_DOWNLOAD))+ job = g_vfs_job_download_new (connection, message, backend);+ else if (dbus_message_is_method_call (message,+ G_VFS_DBUS_MOUNT_INTERFACE, G_VFS_DBUS_MOUNT_OP_MOVE)) job = g_vfs_job_move_new (connection, message, backend); else if (dbus_message_is_method_call (message,diff --git a/daemon/gvfsbackend.h b/daemon/gvfsbackend.hindex d8c7867..599220e 100644--- a/daemon/gvfsbackend.h+++ b/daemon/gvfsbackend.h@@ -65,6 +65,7 @@ typedef struct _GVfsJobMakeDirectory GVfsJobMakeDirectory; typedef struct _GVfsJobMakeSymlink GVfsJobMakeSymlink; typedef struct _GVfsJobCopy GVfsJobCopy; typedef struct _GVfsJobUpload GVfsJobUpload;+typedef struct _GVfsJobDownload GVfsJobDownload; typedef struct _GVfsJobMove GVfsJobMove; typedef struct _GVfsJobSetAttribute GVfsJobSetAttribute; typedef struct _GVfsJobQueryAttributes GVfsJobQueryAttributes;@@ -297,6 +298,20 @@ struct _GVfsBackendClass GFileCopyFlags flags, GFileProgressCallback progress_callback, gpointer progress_callback_data);+ void (*download) (GVfsBackend *backend,+ GVfsJobDownload *job,+ const char *source,+ const char *local_destination,+ GFileCopyFlags flags,+ GFileProgressCallback progress_callback,+ gpointer progress_callback_data);+ gboolean (*try_download) (GVfsBackend *backend,+ GVfsJobDownload *job,+ const char *source,+ const char *local_destination,+ GFileCopyFlags flags,+ GFileProgressCallback progress_callback,+ gpointer progress_callback_data); void (*upload) (GVfsBackend *backend, GVfsJobUpload *job, const char *destination,diff --git a/daemon/gvfsbackendhttp.c b/daemon/gvfsbackendhttp.cindex 7e91a05..1d46924 100644--- a/daemon/gvfsbackendhttp.c+++ b/daemon/gvfsbackendhttp.c@@ -1,5 +1,5 @@ /* GIO - GLib Input, Output and Streaming Library- * + * * Copyright (C) 2008 Red Hat, Inc. * * This library is free software; you can redistribute it and/or@@ -81,7 +81,7 @@ g_vfs_backend_http_init (GVfsBackendHttp *backend) { const char *debug; - g_vfs_backend_set_user_visible (G_VFS_BACKEND (backend), FALSE); + g_vfs_backend_set_user_visible (G_VFS_BACKEND (backend), FALSE); backend->session = soup_session_sync_new_with_options ("user-agent", "gvfs/" VERSION,@@ -214,7 +214,7 @@ http_error_code_from_status (guint status) case SOUP_STATUS_NOT_FOUND: case SOUP_STATUS_GONE:- return G_IO_ERROR_NOT_FOUND; + return G_IO_ERROR_NOT_FOUND; case SOUP_STATUS_GATEWAY_TIMEOUT: return G_IO_ERROR_TIMED_OUT;@@ -229,6 +229,11 @@ g_vfs_job_failed_from_http_status (GVfsJob *job, guint status_code, const char * { switch (status_code) { + case SOUP_STATUS_CANCELLED:+ g_vfs_job_failed_literal (job, G_IO_ERROR, G_IO_ERROR_CANCELLED,+ _("Operation was cancelled"));+ break;+ case SOUP_STATUS_NOT_FOUND: g_vfs_job_failed_literal (job, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, message);@@ -263,7 +268,7 @@ http_backend_queue_message (GVfsBackend *backend, { GVfsBackendHttp *op_backend = G_VFS_BACKEND_HTTP (backend); - soup_session_queue_message (op_backend->session_async, msg, + soup_session_queue_message (op_backend->session_async, msg, callback, user_data); } /* ************************************************************************* */@@ -310,9 +315,9 @@ try_mount (GVfsBackend *backend, real_mount_spec->mount_prefix = g_mount_spec_canonicalize_path (path); g_free (path); }- + g_vfs_backend_set_mount_spec (backend, real_mount_spec);- + op_backend->mount_base = uri; g_vfs_job_succeeded (G_VFS_JOB (job));@@ -331,7 +336,7 @@ open_for_read_ready (GObject *source_object, gboolean can_seek; GError *error; - stream = G_INPUT_STREAM (source_object); + stream = G_INPUT_STREAM (source_object); error = NULL; job = G_VFS_JOB (user_data); @@ -356,7 +361,7 @@ open_for_read_ready (GObject *source_object, g_vfs_job_succeeded (job); } -static gboolean +static gboolean try_open_for_read (GVfsBackend *backend, GVfsJobOpenForRead *job, const char *filename)@@ -393,7 +398,7 @@ read_ready (GObject *source_object, GError *error; gssize nread; - stream = G_INPUT_STREAM (source_object); + stream = G_INPUT_STREAM (source_object); error = NULL; job = G_VFS_JOB (user_data); @@ -498,7 +503,7 @@ close_read_ready (GObject *source_object, g_object_unref (stream); } -static gboolean +static gboolean try_close_read (GVfsBackend *backend, GVfsJobCloseRead *job, GVfsBackendHandle handle)@@ -547,7 +552,7 @@ query_info_ready (SoupSession *session, g_print ("basename:%s\n", basename); /* read http/1.1 rfc, until then we copy the local files- * behaviour */ + * behaviour */ if (basename != NULL && g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME))@@ -572,7 +577,7 @@ query_info_ready (SoupSession *session, char *edit_name = g_filename_display_name (basename); g_file_info_set_edit_name (info, edit_name); g_free (edit_name);- } + } g_free (basename); @@ -647,16 +652,217 @@ try_query_info (GVfsBackend *backend, return TRUE; } +typedef struct {++ GVfsJobDownload *job;+ GFileCopyFlags flags;+ const char *destination;++ SoupSession *session;++ GOutputStream *out;++ GFileProgressCallback progress_callback;+ gpointer progress_callback_data;++ goffset total_size;+ goffset data_read;++ GError *error;+ GCancellable *cancellable;++} DownloadData;++static void+download_got_headers (SoupMessage *msg,+ gpointer user_data)+{+ DownloadData *data = user_data;+ GFileOutputStream *out;+ GFile *file;+ const char *text;++ if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))+ return;++ file = g_file_new_for_path (data->destination);++ if (data->flags & G_FILE_COPY_OVERWRITE)+ {+ out = g_file_replace (file,+ NULL,+ data->flags & G_FILE_COPY_BACKUP,+ 0,+ data->cancellable,+ &data->error);+ }+ else+ {+ out = g_file_create (file,+ 0,+ data->cancellable,+ &data->error);+ }++ g_object_unref (file);++ if (out == NULL)+ {+ soup_session_cancel_message (data->session, msg, SOUP_STATUS_CANCELLED);+ return;+ }++ data->out = G_OUTPUT_STREAM (out);++ if (data->progress_callback == NULL)+ return;++ text = soup_message_headers_get (msg->response_headers,+ "Content-Length");+ if (text)+ {+ char *endptr = NULL;++ data->total_size = g_ascii_strtoull (text, &endptr, 10);++ if (endptr == text)+ data->total_size = -1;+ }++}++static void+download_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer user_data)+{+ DownloadData *data = user_data;+ gsize bytes_written = 0;+ gboolean res;++ res = g_output_stream_write_all (data->out,+ chunk->data,+ chunk->length,+ &bytes_written,+ data->cancellable,+ &data->error);++ if (res == FALSE)+ {+ soup_session_cancel_message (data->session, msg, SOUP_STATUS_CANCELLED);+ return;+ }++ if (data->progress_callback)+ {+ data->data_read += bytes_written;+ data->progress_callback (data->data_read, data->total_size,+ data->progress_callback_data);+ }+}++static void+download_got_body (SoupMessage *msg,+ gpointer user_data)+{+ DownloadData *data = user_data;+ gboolean res;++ res = g_output_stream_close (data->out, data->cancellable, &data->error);++ if (res == FALSE)+ soup_session_cancel_message (data->session, msg, SOUP_STATUS_CANCELLED);++ g_object_unref (data->out);+ data->out = NULL;+}++static void+download_finished (SoupMessage *msg,+ gpointer user_data)+{+ DownloadData *data = user_data;++ /* In an error case the message will get cancelled+ * and the got_body function not be called so we+ * free the output stream here .. */++ if (data->out != NULL)+ {+ g_output_stream_close (data->out, data->cancellable, NULL);+ g_object_unref (data->out);+ }++}++static void+do_download (GVfsBackend *backend,+ GVfsJobDownload *job,+ const char *source,+ const char *local_destination,+ GFileCopyFlags flags,+ GFileProgressCallback progress_callback,+ gpointer progress_callback_data)+{+ DownloadData data;+ SoupMessage *msg;+ SoupURI *uri;+ guint status;++ uri = http_backend_uri_for_filename (backend, source, FALSE);+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);+ soup_uri_free (uri);++ soup_message_body_set_accumulate (msg->response_body, FALSE);++ g_signal_connect (msg, "got_headers",+ G_CALLBACK (download_got_headers), &data);++ g_signal_connect (msg, "got_chunk",+ G_CALLBACK (download_got_chunk), &data);++ g_signal_connect (msg, "got_body",+ G_CALLBACK (download_got_body), &data);++ g_signal_connect (msg, "finished",+ G_CALLBACK (download_finished), &data);++ memset (&data, 0, sizeof (data));++ data.job = job;+ data.flags = flags;+ data.cancellable = G_VFS_JOB (job)->cancellable;+ data.destination = local_destination;+ data.session = G_VFS_BACKEND_HTTP (backend)->session;+ data.progress_callback_data = progress_callback_data;+ data.progress_callback = progress_callback;+ data.total_size = -1;++ status = http_backend_send_message (backend, msg);++ if (! SOUP_STATUS_IS_SUCCESSFUL (status))+ {+ if (data.error != NULL)+ {+ g_vfs_job_failed_from_error (G_VFS_JOB (job), data.error);+ g_error_free (data.error);+ }+ else+ g_vfs_job_failed_from_http_status (G_VFS_JOB (job), status, msg->reason_phrase);+ }+ else+ g_vfs_job_succeeded (G_VFS_JOB (job));++ g_object_unref (msg);+} static void g_vfs_backend_http_class_init (GVfsBackendHttpClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GVfsBackendClass *backend_class;- + gobject_class->finalize = g_vfs_backend_http_finalize; - backend_class = G_VFS_BACKEND_CLASS (klass); + backend_class = G_VFS_BACKEND_CLASS (klass); backend_class->try_mount = try_mount; backend_class->try_open_for_read = try_open_for_read;@@ -665,4 +871,5 @@ g_vfs_backend_http_class_init (GVfsBackendHttpClass *klass) backend_class->try_close_read = try_close_read; backend_class->try_query_info = try_query_info; + backend_class->download = do_download; }diff --git a/daemon/gvfsjobdownload.c b/daemon/gvfsjobdownload.cnew file mode 100644index 0000000..6828e5e--- /dev/null+++ b/daemon/gvfsjobdownload.c@@ -0,0 +1,211 @@+/* GIO - GLib Input, Output and Streaming Library+ *+ * Copyright (C) 2006-2007 Red Hat, Inc.+ *+ * This library is free software; you can redistribute it and/or+ * modify it under the terms of the GNU Lesser General Public+ * License as published by the Free Software Foundation; either+ * version 2 of the License, or (at your option) any later version.+ *+ * This library is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU+ * Lesser General Public License for more details.+ *+ * You should have received a copy of the GNU Lesser General+ * Public License along with this library; if not, write to the+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,+ * Boston, MA 02111-1307, USA.+ *+ * Author: Alexander Larsson <alexl@redhat.com>+ */++#include <config.h>++#include <strings.h>+#include <unistd.h>+#include <sys/types.h>+#include <sys/socket.h>+#include <sys/un.h>++#include <glib.h>+#include <dbus/dbus.h>+#include <glib/gi18n.h>+#include "gvfsjobdownload.h"+#include "gdbusutils.h"+#include "gvfsdaemonprotocol.h"++G_DEFINE_TYPE (GVfsJobDownload, g_vfs_job_download, G_VFS_TYPE_JOB_DBUS)++static void run (GVfsJob *job);+static gboolean try (GVfsJob *job);+static DBusMessage *create_reply (GVfsJob *job,+ DBusConnection *connection,+ DBusMessage *message);++static void+g_vfs_job_download_finalize (GObject *object)+{+ GVfsJobDownload *job;++ job = G_VFS_JOB_DOWNLOAD (object);++ g_free (job->local_destination);+ g_free (job->source);+ g_free (job->callback_obj_path);++ if (G_OBJECT_CLASS (g_vfs_job_download_parent_class)->finalize)+ (*G_OBJECT_CLASS (g_vfs_job_download_parent_class)->finalize) (object);+}++static void+g_vfs_job_download_class_init (GVfsJobDownloadClass *klass)+{+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);+ GVfsJobClass *job_class = G_VFS_JOB_CLASS (klass);+ GVfsJobDBusClass *job_dbus_class = G_VFS_JOB_DBUS_CLASS (klass);++ gobject_class->finalize = g_vfs_job_download_finalize;+ job_class->run = run;+ job_class->try = try;+ job_dbus_class->create_reply = create_reply;+}++static void+g_vfs_job_download_init (GVfsJobDownload *job)+{+}++GVfsJob *+g_vfs_job_download_new (DBusConnection *connection,+ DBusMessage *message,+ GVfsBackend *backend)+{+ GVfsJobDownload *job;+ DBusMessage *reply;+ DBusError derror;+ int path1_len, path2_len;+ const char *path1_data, *path2_data, *callback_obj_path;+ dbus_uint32_t flags;++ dbus_error_init (&derror);+ if (!dbus_message_get_args (message, &derror,+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,+ &path1_data, &path1_len,+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,+ &path2_data, &path2_len,+ DBUS_TYPE_UINT32, &flags,+ DBUS_TYPE_OBJECT_PATH, &callback_obj_path,+ 0))+ {+ reply = dbus_message_new_error (message,+ derror.name,+ derror.message);+ dbus_error_free (&derror);++ dbus_connection_send (connection, reply, NULL);+ return NULL;+ }++ job = g_object_new (G_VFS_TYPE_JOB_DOWNLOAD,+ "message", message,+ "connection", connection,+ NULL);++ job->source = g_strndup (path1_data, path1_len);+ job->local_destination = g_strndup (path2_data, path2_len);+ job->backend = backend;+ job->flags = flags;+ if (strcmp (callback_obj_path, "/org/gtk/vfs/void") != 0)+ job->callback_obj_path = g_strdup (callback_obj_path);++ return G_VFS_JOB (job);+}++static void+progress_callback (goffset current_num_bytes,+ goffset total_num_bytes,+ gpointer user_data)+{+ GVfsJob *job = G_VFS_JOB (user_data);+ GVfsJobDBus *dbus_job = G_VFS_JOB_DBUS (job);+ GVfsJobDownload *op_job = G_VFS_JOB_DOWNLOAD (job);+ dbus_uint64_t current_dbus, total_dbus;+ DBusMessage *message;++ g_print ("progress_callback %d/%d\n", (int)current_num_bytes, (int)total_num_bytes);++ if (op_job->callback_obj_path == NULL)+ return;++ message =+ dbus_message_new_method_call (dbus_message_get_sender (dbus_job->message),+ op_job->callback_obj_path,+ G_VFS_DBUS_PROGRESS_INTERFACE,+ G_VFS_DBUS_PROGRESS_OP_PROGRESS);+ dbus_message_set_no_reply (message, TRUE);++ current_dbus = current_num_bytes;+ total_dbus = total_num_bytes;+ dbus_message_append_args (message,+ DBUS_TYPE_UINT64, ¤t_dbus,+ DBUS_TYPE_UINT64, &total_dbus,+ 0);++ /* Queues reply (threadsafely), actually sends it in mainloop */+ dbus_connection_send (dbus_job->connection, message, NULL);+ dbus_message_unref (message);+}++static void+run (GVfsJob *job)+{+ GVfsJobDownload *op_job = G_VFS_JOB_DOWNLOAD (job);+ GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend);++ if (class->download == NULL)+ {+ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,+ _("Operation not supported by backend"));+ return;+ }++ class->download (op_job->backend,+ op_job,+ op_job->source,+ op_job->local_destination,+ op_job->flags,+ progress_callback,+ job);+}++static gboolean+try (GVfsJob *job)+{+ GVfsJobDownload *op_job = G_VFS_JOB_DOWNLOAD (job);+ GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend);++ if (class->try_download == NULL)+ return FALSE;++ return class->try_download (op_job->backend,+ op_job,+ op_job->source,+ op_job->local_destination,+ op_job->flags,+ progress_callback,+ job);+}++/* Might be called on an i/o thread */+static DBusMessage *+create_reply (GVfsJob *job,+ DBusConnection *connection,+ DBusMessage *message)+{+ DBusMessage *reply;++ reply = dbus_message_new_method_return (message);++ return reply;+}diff --git a/daemon/gvfsjobdownload.h b/daemon/gvfsjobdownload.hnew file mode 100644index 0000000..a92bb94--- /dev/null+++ b/daemon/gvfsjobdownload.h@@ -0,0 +1,66 @@+/* GIO - GLib Input, Output and Streaming Library+ *+ * Copyright (C) 2006-2007 Red Hat, Inc.+ *+ * This library is free software; you can redistribute it and/or+ * modify it under the terms of the GNU Lesser General Public+ * License as published by the Free Software Foundation; either+ * version 2 of the License, or (at your option) any later version.+ *+ * This library is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU+ * Lesser General Public License for more details.+ *+ * You should have received a copy of the GNU Lesser General+ * Public License along with this library; if not, write to the+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,+ * Boston, MA 02111-1307, USA.+ *+ * Author: Alexander Larsson <alexl@redhat.com>+ */++#ifndef __G_VFS_JOB_DOWNLOAD_H__+#define __G_VFS_JOB_DOWNLOAD_H__++#include <gio/gio.h>+#include <gvfsjob.h>+#include <gvfsjobdbus.h>+#include <gvfsbackend.h>++G_BEGIN_DECLS++#define G_VFS_TYPE_JOB_DOWNLOAD (g_vfs_job_download_get_type ())+#define G_VFS_JOB_DOWNLOAD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_VFS_TYPE_JOB_DOWNLOAD, GVfsJobDownload))+#define G_VFS_JOB_DOWNLOAD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_JOB_DOWNLOAD, GVfsJobDownloadClass))+#define G_VFS_IS_JOB_DOWNLOAD(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_VFS_TYPE_JOB_DOWNLOAD))+#define G_VFS_IS_JOB_DOWNLOAD_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_VFS_TYPE_JOB_DOWNLOAD))+#define G_VFS_JOB_DOWNLOAD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_VFS_TYPE_JOB_DOWNLOAD, GVfsJobDownloadClass))++typedef struct _GVfsJobDownloadClass GVfsJobDownloadClass;++struct _GVfsJobDownload+{+ GVfsJobDBus parent_instance;++ GVfsBackend *backend;+ char *source;+ char *local_destination;+ GFileCopyFlags flags;+ char *callback_obj_path;+};++struct _GVfsJobDownloadClass+{+ GVfsJobDBusClass parent_class;+};++GType g_vfs_job_download_get_type (void) G_GNUC_CONST;++GVfsJob *g_vfs_job_download_new (DBusConnection *connection,+ DBusMessage *message,+ GVfsBackend *backend);++G_END_DECLS++#endif /* __G_VFS_JOB_DOWNLOAD_H__ */