]> spindle.queued.net Git - midori/commitdiff
Rework downloading into Midori.Download interface
authorChristian Dywan <christian@twotoasts.de>
Sun, 9 Sep 2012 11:42:59 +0000 (13:42 +0200)
committerChristian Dywan <christian@twotoasts.de>
Sun, 9 Sep 2012 12:07:30 +0000 (14:07 +0200)
Midori.URI
    get_folder
Midori.Download
    is_finished
    get/set_type
    get_progress
    get_tooltip
      Consistent estimation of remaining time and speed.
    get_content_type
      Icons in dialog and panel.
    has_wrong_checksum
      Verification in both panel and toolbar.
    action_clear, action_stock_id, open
      Consistent behavior in both panel and toolbar.
    fallback_extension
    clean_filename
        Merged two separate functions.
    get_suggested_filename
    get_filename_suggestion_for_uri
        Now handles MIME types.
    get_extension_for_uri
    get_unique_filename
        Renamed from prepare_filename.
    prepare_destination_uri
    has_enough_space

katze/midori-uri.vala
midori/midori-browser.c
midori/midori-download.vala [new file with mode: 0644]
midori/midori-view.c
midori/sokoke.c
midori/sokoke.h
panels/midori-transfers.c
po/POTFILES.in
toolbars/midori-transferbar.c

index 21681cb04f15f4483453e40517e9f0ddaa055db4..adefff837ca6a2087f92cd346a76b7583ea23b1d 100644 (file)
@@ -145,6 +145,21 @@ namespace Midori {
              && uri.chr (-1, ' ') == null
              && (URI.is_location (uri) || uri.chr (-1, '.') != null);
         }
+
+        public static string? get_folder (string uri) {
+            /* Base the start folder on the current view's uri if it is local */
+            try {
+                string? filename = Filename.from_uri (uri);
+                if (filename != null) {
+                    string? dirname = Path.get_dirname (filename);
+                    if (dirname != null && FileUtils.test (dirname, FileTest.IS_DIR))
+                        return dirname;
+                }
+            }
+            catch (Error error) { }
+            return null;
+        }
+
         public static GLib.ChecksumType get_fingerprint (string uri,
             out string checksum, out string label) {
 
index 0255b023dcfd55a0df70873bea341c11d82daaa2..a2d7ea24626f667cef0761294596dc44caf94fa4 100644 (file)
@@ -983,54 +983,8 @@ midori_browser_prepare_download (MidoriBrowser*  browser,
                                  const gchar*    uri)
 
 {
-    guint64 total_size = webkit_download_get_total_size (download);
-    GFile* file = g_file_new_for_uri (uri);
-    GFile* folder = g_file_get_parent (file);
-    GError* error = NULL;
-    GFileInfo* info = g_file_query_filesystem_info (folder,
-        G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, &error);
-    guint64 free_space = g_file_info_get_attribute_uint64 (info,
-        G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
-    gchar* path = g_file_get_path (folder);
-    gboolean can_write = g_access (path, W_OK) == 0;
-    g_free (path);
-    g_object_unref (file);
-    g_object_unref (folder);
-    if (free_space < total_size || !can_write)
-    {
-        gchar* message;
-        gchar* detailed_message;
-
-        if (!can_write)
-        {
-            message = g_strdup_printf (
-                _("The file \"%s\" can't be saved in this folder."), &uri[7]);
-            detailed_message = g_strdup_printf (
-                _("You don't have permission to write in this location."));
-        }
-        else if (free_space < total_size)
-        {
-            gchar* total_size_string = g_format_size (total_size);
-            gchar* free_space_string = g_format_size (free_space);
-            message = g_strdup_printf (
-                _("There is not enough free space to download \"%s\"."),
-                  &uri[7]);
-            detailed_message = g_strdup_printf (
-                _("The file needs %s but only %s are left."),
-                  total_size_string, free_space_string);
-            g_free (total_size_string);
-            g_free (free_space_string);
-        }
-        else
-            g_assert_not_reached ();
-
-        sokoke_message_dialog (GTK_MESSAGE_ERROR, message, detailed_message, FALSE);
-        g_free (message);
-        g_free (detailed_message);
-        g_object_unref (download);
+    if (!midori_download_has_enough_space (download, uri))
         return FALSE;
-    }
-
     webkit_download_set_destination_uri (download, uri);
     g_signal_emit (browser, signals[ADD_DOWNLOAD], 0, download);
     midori_transferbar_add_download_item (MIDORI_TRANSFERBAR (browser->transferbar), download);
@@ -1039,61 +993,6 @@ midori_browser_prepare_download (MidoriBrowser*  browser,
     return TRUE;
 }
 
-static gchar*
-midori_browser_get_folder_for_uri (MidoriBrowser* browser,
-                                   const gchar*   uri)
-{
-    if (uri)
-    {
-        /* Base the start folder on the current view's uri if it is local */
-        gchar* filename = g_filename_from_uri (uri, NULL, NULL);
-        if (filename)
-        {
-            gchar* dirname = g_path_get_dirname (filename);
-            g_free (filename);
-            if (dirname && g_file_test (dirname, G_FILE_TEST_IS_DIR))
-                return dirname;
-        }
-    }
-    return katze_object_get_string (browser->settings, "download-folder");
-}
-
-static gchar*
-midori_browser_fixup_filename (gchar* filename)
-{
-    #ifdef G_OS_WIN32
-    g_strdelimit (filename, "/\\<>:\"|?*", '_');
-    #else
-    g_strdelimit (filename, "/", '_');
-    #endif
-    return filename;
-}
-
-static gchar*
-midori_browser_get_filename_suggestion_for_uri (MidoriView*  view,
-                                                const gchar* uri)
-{
-    /* Try to provide a good default filename, UTF-8 encoded */
-    gchar* filename = soup_uri_decode (uri);
-    gchar* last_slash = g_strrstr (filename, "/") + 1;
-    /* Take the rest of the URI if needed */
-    if (*last_slash == '\0')
-    {
-        const gchar* extension = midori_view_fallback_extension (view, NULL);
-        gchar* guessed;
-        last_slash = midori_browser_fixup_filename (filename);
-        guessed = g_strconcat (filename, extension, NULL);
-        g_free (filename);
-        return guessed;
-    }
-    last_slash = g_strdup (last_slash);
-    g_free (filename);
-    return midori_browser_fixup_filename (last_slash);
-}
-
-static gchar*
-midori_browser_download_prepare_filename (gchar* filename);
-
 static void
 midori_browser_save_resources (MidoriView*  view,
                                const gchar* folder)
@@ -1115,11 +1014,11 @@ midori_browser_save_resources (MidoriView*  view,
         if (!g_strcmp0 (webkit_web_resource_get_uri (resource), "about:blank"))
             continue;
 
-        /* FIXME: mime type fallback should respect the resource's type */
-        gchar* sub_filename = midori_browser_get_filename_suggestion_for_uri (
-            view, webkit_web_resource_get_uri (resource));
+        gchar* sub_filename = midori_download_get_filename_suggestion_for_uri (
+            webkit_web_resource_get_mime_type (resource),
+            webkit_web_resource_get_uri (resource));
         gchar* sub_path = g_build_filename (folder, sub_filename, NULL);
-        sub_path = midori_browser_download_prepare_filename (sub_path);
+        sub_path = midori_download_get_unique_filename (sub_path);
         if (data)
         {
             GError* error = NULL;
@@ -1155,6 +1054,10 @@ midori_browser_save_uri (MidoriBrowser* browser,
     dialog = sokoke_file_chooser_dialog_new (_("Save file as"),
         GTK_WINDOW (browser), GTK_FILE_CHOOSER_ACTION_SAVE);
     gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
+
+    if (uri == NULL)
+        uri = midori_view_get_display_uri (view);
+
     if (midori_view_can_view_source (view))
     {
         file_only = FALSE;
@@ -1162,21 +1065,26 @@ midori_browser_save_uri (MidoriBrowser* browser,
         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), TRUE);
         gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), checkbox);
     }
+
     if (last_dir && *last_dir)
         gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), last_dir);
     else
     {
-        gchar* dirname = midori_browser_get_folder_for_uri (browser, uri);
+        gchar* dirname = midori_uri_get_folder (uri);
+        if (dirname == NULL)
+            dirname = katze_object_get_string (browser->settings, "download-folder");
         gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), dirname);
         g_free (dirname);
     }
 
-    if (uri == NULL)
-        uri = midori_view_get_display_uri (view);
     if (!file_only && !g_str_equal (title, uri))
-        filename = midori_browser_fixup_filename (g_strdup (title));
+        filename = midori_download_clean_filename (title);
     else
-        filename = midori_browser_get_filename_suggestion_for_uri (view, uri);
+    {
+        gchar* mime_type = katze_object_get_object (view, "mime-type");
+        filename = midori_download_get_filename_suggestion_for_uri (mime_type, uri);
+        g_free (mime_type);
+    }
     gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), filename);
     g_free (filename);
 
@@ -1437,70 +1345,6 @@ midori_browser_download_status_cb (WebKitDownload*  download,
     }
 }
 
-static gchar*
-midori_browser_download_prepare_filename (gchar* filename)
-{
-    if (g_file_test (filename, G_FILE_TEST_EXISTS))
-    {
-        int i = 1;
-        const gchar* dot_pos;
-        const gchar* last_separator;
-        gchar* serial;
-        GString* tmp_filename;
-        gssize position;
-
-        last_separator = strrchr (filename, G_DIR_SEPARATOR);
-        dot_pos = strrchr ((last_separator) ? last_separator : filename, '.');
-        position = dot_pos ? (dot_pos - filename) : (gssize) strlen (filename);
-        tmp_filename = g_string_new (NULL);
-
-        do
-        {
-            serial = g_strdup_printf ("-%d", i++);
-            g_string_assign (tmp_filename, filename);
-            g_string_insert (tmp_filename, position, serial);
-            g_free (serial);
-        } while (g_file_test (tmp_filename->str, G_FILE_TEST_EXISTS));
-
-        g_free (filename);
-        filename = g_string_free (tmp_filename, FALSE);
-    }
-    return filename;
-}
-
-static gchar*
-midori_browser_download_prepare_destination_uri (WebKitDownload* download,
-                                                 const gchar*    folder)
-{
-    gchar* suggested_filename;
-    GFile* file_source;
-    gchar* file_basename;
-    const gchar* download_dir = NULL;
-    gchar* destination_uri;
-    gchar* destination_filename;
-
-    suggested_filename = sokoke_get_download_filename (download);
-    file_source = g_file_new_for_uri (suggested_filename);
-    g_free (suggested_filename);
-    file_basename = g_file_get_basename (file_source);
-    if (folder == NULL)
-    {
-        download_dir = midori_paths_get_tmp_dir ();
-        katze_mkdir_with_parents (download_dir, 0700);
-    }
-    else
-        download_dir = folder;
-    destination_filename = g_build_filename (download_dir, file_basename, NULL);
-    destination_filename = midori_browser_download_prepare_filename (destination_filename);
-    destination_uri = g_filename_to_uri (destination_filename, NULL, NULL);
-
-    g_free (file_basename);
-    g_free (destination_filename);
-    g_object_unref (file_source);
-
-    return destination_uri;
-}
-
 static gboolean
 midori_browser_remove_tab_idle (gpointer view)
 {
@@ -1517,8 +1361,7 @@ midori_view_download_requested_cb (GtkWidget*      view,
                                    WebKitDownload* download,
                                    MidoriBrowser*  browser)
 {
-    MidoriDownloadType type = GPOINTER_TO_INT (
-        g_object_get_data (G_OBJECT (download), "midori-download-type"));
+    MidoriDownloadType type = midori_download_get_type (download);
     GtkWidget* web_view;
     WebKitWebFrame* web_frame;
     WebKitWebDataSource* datasource;
@@ -1533,7 +1376,7 @@ midori_view_download_requested_cb (GtkWidget*      view,
     else if (type == MIDORI_DOWNLOAD_OPEN_IN_VIEWER)
     {
         gchar* destination_uri =
-            midori_browser_download_prepare_destination_uri (download, NULL);
+            midori_download_prepare_destination_uri (download, NULL);
         midori_browser_prepare_download (browser, download, destination_uri);
         g_signal_connect (download, "notify::status",
             G_CALLBACK (midori_browser_download_status_cb), GTK_WIDGET (browser));
@@ -1555,15 +1398,16 @@ midori_view_download_requested_cb (GtkWidget*      view,
                 gtk_file_chooser_set_do_overwrite_confirmation (
                     GTK_FILE_CHOOSER (dialog), TRUE);
                 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
-                folder = midori_browser_get_folder_for_uri (browser,
-                    webkit_download_get_uri (download));
+                folder = midori_uri_get_folder (webkit_download_get_uri (download));
+                if (folder == NULL)
+                    folder = katze_object_get_string (browser->settings, "download-folder");
                 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), folder);
                 g_free (folder);
                 g_signal_connect (dialog, "destroy",
                                   G_CALLBACK (gtk_widget_destroyed), &dialog);
             }
             g_object_set_data (G_OBJECT (dialog), "download", download);
-            filename = sokoke_get_download_filename (download);
+            filename = midori_download_get_suggested_filename (download);
             gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), filename);
             g_free (filename);
 
@@ -1589,7 +1433,7 @@ midori_view_download_requested_cb (GtkWidget*      view,
             gchar* folder = type == MIDORI_DOWNLOAD_OPEN ? NULL
               : katze_object_get_string (browser->settings, "download-folder");
             gchar* destination_uri =
-                midori_browser_download_prepare_destination_uri (download, folder);
+                midori_download_prepare_destination_uri (download, folder);
             midori_browser_prepare_download (browser, download, destination_uri);
             g_free (destination_uri);
         }
diff --git a/midori/midori-download.vala b/midori/midori-download.vala
new file mode 100644 (file)
index 0000000..994a7ce
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ Copyright (C) 2012 Christian Dywan <christian@twotoasts.de>
+
+ 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.1 of the License, or (at your option) any later version.
+
+ See the file COPYING for the full license text.
+*/
+
+namespace Sokoke {
+    extern static bool show_uri (Gdk.Screen screen, string uri, uint32 timestamp) throws Error;
+    extern static bool message_dialog (Gtk.MessageType type, string short, string detailed, bool modal);
+}
+
+namespace Midori {
+    namespace Download {
+        public static bool is_finished (WebKit.Download download) {
+            switch (download.status) {
+                case WebKit.DownloadStatus.FINISHED:
+                case WebKit.DownloadStatus.CANCELLED:
+                case WebKit.DownloadStatus.ERROR:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        public static int get_type (WebKit.Download download) {
+            return download.get_data<int> ("midori-download-type");
+        }
+
+        public static void set_type (WebKit.Download download, int type) {
+            download.set_data<int> ("midori-download-type", type);
+        }
+
+        public static double get_progress (WebKit.Download download) {
+            /* Avoid a bug in WebKit */
+            if (download.status == WebKit.DownloadStatus.CREATED)
+                return 0.0;
+            return download.progress;
+        }
+
+        public static string get_tooltip (WebKit.Download download) {
+            string filename = Path.get_basename (download.destination_uri);
+            /* i18n: Download tooltip (size): 4KB of 43MB */
+            string size = _("%s of %s").printf (
+                format_size (download.current_size),
+                format_size (download.total_size));
+
+            uint64 total_size = download.total_size, current_size = download.current_size;
+            double elapsed = download.get_elapsed_time (),
+               diff = elapsed / current_size,
+               estimated = (total_size - current_size) * diff;
+            int hour = 3600, minute = 60;
+            int hours = (int)(estimated / hour),
+                minutes = (int)((estimated - (hours * hour)) / minute),
+                seconds = (int)((estimated - (hours * hour) - (minutes * minute)));
+            string hours_ = ngettext ("%d hour", "%d hours", hours).printf (hours);
+            string minutes_ = ngettext ("%d minute", "%d minutes", minutes).printf (minutes);
+            string seconds_ = ngettext ("%d second", "%d seconds", seconds).printf (seconds);
+            double last_time = download.get_data<int> ("last-time");
+            uint64 last_size = download.get_data<uint64> ("last-size");
+
+            string eta = "";
+            if (estimated > 0) {
+                if (hours > 0)
+                    eta = hours_ + ", " + minutes_;
+                else if (minutes >= 10)
+                    eta = minutes_;
+                else if (minutes < 10 && minutes > 0)
+                    eta = minutes_ + ", " + seconds_;
+                else if (seconds > 0)
+                    eta = seconds_;
+                if (eta != "")
+            /* i18n: Download tooltip (estimated time) : - 1 hour, 5 minutes remaning */
+                    eta = _(" - %s remaining").printf (eta);
+            }
+
+            string speed;
+            if (elapsed != last_time)
+                speed = format_size ((int)((current_size - last_size) / (elapsed - last_time)));
+            else
+                /* i18n: Unknown number of bytes, used for transfer rate like ?B/s */
+                speed = _("?B");
+            /* i18n: Download tooltip (transfer rate): (130KB/s) */
+            speed = _(" (%s/s)").printf (speed);
+            if (elapsed - last_time > 5.0) {
+                download.set_data<int> ("last-time", (int)elapsed);
+                download.set_data<uint64> ("last-size", current_size);
+            }
+
+            return "%s\n%s %s%s".printf (filename, size, speed, eta);
+        }
+
+        public static string get_content_type (WebKit.Download download, string? mime_type) {
+            string? content_type = ContentType.guess (download.suggested_filename, null, null);
+            if (content_type == null) {
+                content_type = ContentType.from_mime_type (mime_type);
+                if (content_type == null)
+                    content_type = ContentType.from_mime_type ("application/octet-stream");
+            }
+            return content_type;
+        }
+
+        public static bool has_wrong_checksum (WebKit.Download download) {
+            int status = download.get_data<int> ("checksum-status");
+            if (status == 0) {
+                /* Link Fingerprint */
+                string? original_uri = download.network_request.get_data<string> ("midori-original-uri");
+                if (original_uri == null)
+                    original_uri = download.get_uri ();
+                string? fingerprint;
+                ChecksumType checksum_type = URI.get_fingerprint (original_uri, out fingerprint, null);
+                /* By default, no wrong checksum */
+                status = 2;
+                if (fingerprint != null) {
+                    try {
+                        string filename = Filename.from_uri (download.destination_uri);
+                        string contents;
+                        size_t length;
+                        bool y = FileUtils.get_contents (filename, out contents, out length);
+                        string checksum = Checksum.compute_for_string (checksum_type, contents, length);
+                        /* Checksums are case-insensitive */
+                        if (!y || fingerprint.ascii_casecmp (checksum) != 0)
+                            status = 1; /* wrong checksum */
+                    }
+                    catch (Error error) {
+                        status = 1; /* wrong checksum */
+                    }
+                }
+                download.set_data<int> ("checksum-status", status);
+            }
+            return status == 1;
+        }
+
+        public static bool action_clear (WebKit.Download download, Gtk.Widget widget) throws Error {
+            switch (download.status) {
+                case WebKit.DownloadStatus.CREATED:
+                case WebKit.DownloadStatus.STARTED:
+                    download.cancel ();
+                    break;
+                case WebKit.DownloadStatus.FINISHED:
+                    if (open (download, widget))
+                        return true;
+                    break;
+                case WebKit.DownloadStatus.CANCELLED:
+                    return true;
+                default:
+                    critical ("action_clear: %d", download.status);
+                    warn_if_reached ();
+                    break;
+            }
+            return false;
+        }
+
+        public static string action_stock_id (WebKit.Download download) {
+            switch (download.status) {
+                case WebKit.DownloadStatus.CREATED:
+                case WebKit.DownloadStatus.STARTED:
+                    return Gtk.Stock.CANCEL;
+                case WebKit.DownloadStatus.FINISHED:
+                    if (has_wrong_checksum (download))
+                        return Gtk.Stock.DIALOG_WARNING;
+                    return Gtk.Stock.OPEN;
+                case WebKit.DownloadStatus.CANCELLED:
+                    return Gtk.Stock.CLEAR;
+                default:
+                    critical ("action_stock_id: %d", download.status);
+                    warn_if_reached ();
+                    return Gtk.Stock.MISSING_IMAGE;
+            }
+        }
+
+        public static bool open (WebKit.Download download, Gtk.Widget widget) throws Error {
+            if (!has_wrong_checksum (download))
+                return Sokoke.show_uri (widget.get_screen (),
+                    download.destination_uri, Gtk.get_current_event_time ());
+
+            Sokoke.message_dialog (Gtk.MessageType.WARNING,
+                _("The downloaded file is erroneous."),
+    _("The checksum provided with the link did not match. This means the file is probably incomplete or was modified afterwards."),
+                true);
+            return false;
+        }
+
+        public unowned string fallback_extension (string? extension, string mime_type) {
+            if (extension != null && extension[0] != '\0')
+                return extension;
+            if ("css" in mime_type)
+                return ".css";
+            if ("javascript" in mime_type)
+                return ".js";
+            if ("html" in mime_type)
+                return ".htm";
+            if ("plain" in mime_type)
+                return ".txt";
+            return "";
+        }
+
+        public string clean_filename (string filename) {
+            #if HAVE_WIN32
+            return filename.delimit ("/\\<>:\"|?*", '_');
+            #else
+            return filename.delimit ("/", '_');
+            #endif
+        }
+
+        public string get_suggested_filename (WebKit.Download download) {
+            /* https://bugs.webkit.org/show_bug.cgi?id=83161
+               https://d19vezwu8eufl6.cloudfront.net/nlp/slides%2F03-01-FormalizingNB.pdf */
+            return clean_filename (download.get_suggested_filename ());
+        }
+
+        public string get_filename_suggestion_for_uri (string mime_type, string uri) {
+            /* Try to provide a good default filename, UTF-8 encoded */
+            string filename = clean_filename (Soup.URI.decode (uri));
+            /* Take the rest of the URI if needed */
+            if (filename.has_suffix ("/"))
+                return filename + fallback_extension (null, mime_type);
+            return filename;
+        }
+
+        public static string? get_extension_for_uri (string uri, out string basename) {
+            if (&basename != null)
+                basename = null;
+            /* Find the last slash and the last period *after* the last slash. */
+            int last_slash = uri.last_index_of_char ('/');
+            /* Huh, URI without slashes? */
+            if (last_slash == -1)
+                return null;
+            int period = uri.last_index_of_char ('.', last_slash);
+            if (period == -1)
+                return null;
+            /* The extension, or "." if it ended with a period */
+            string extension = uri.substring (period, -1);
+            if (&basename != null)
+                basename = uri.substring (0, period);
+            return extension;
+
+        }
+
+        public string get_unique_filename (string filename) {
+            if (Posix.access (filename, Posix.F_OK) != 0) {
+                string basename;
+                string? extension = get_extension_for_uri (filename, out basename);
+                string? new_filename = null;
+                int i = -1;
+                do {
+                    new_filename = "%s-%d%s".printf (basename, i++, extension ?? "");
+                } while (Posix.access (new_filename, Posix.F_OK) == 0);
+                return new_filename;
+            }
+            return filename;
+        }
+
+        public string prepare_destination_uri (WebKit.Download download, string? folder) {
+            string suggested_filename = get_suggested_filename (download);
+            string basename = File.new_for_uri (suggested_filename).get_basename ();
+            string download_dir;
+            if (folder == null) {
+                download_dir = Paths.get_tmp_dir ();
+                Katze.mkdir_with_parents (download_dir, 0700);
+            }
+            else
+                download_dir = folder;
+            string destination_filename = Path.build_filename (download_dir, basename);
+            try {
+                return Filename.to_uri (get_unique_filename (destination_filename));
+            }
+            catch (Error error) {
+                return "file://" + destination_filename;
+            }
+        }
+
+        public static bool has_enough_space (WebKit.Download download, string uri) {
+            var folder = File.new_for_uri (uri).get_parent ();
+            uint64 free_space;
+            try {
+                var info = folder.query_filesystem_info ("filesystem::free");
+                free_space = info.get_attribute_uint64 ("filesystem::free");
+            }
+            catch (Error error) {
+                free_space = 0;
+            }
+            bool can_write = Posix.access (folder.get_path (), Posix.F_OK) == 0;
+            if (free_space < download.total_size || !can_write) {
+                string message;
+                string detailed_message;
+                if (!can_write) {
+                    message = _("The file \"%s\" can't be saved in this folder.").printf (
+                        Path.get_basename (uri));
+                    detailed_message = _("You don't have permission to write in this location.");
+                }
+                else if (free_space < download.total_size) {
+                    message = _("There is not enough free space to download \"%s\".").printf (
+                        Path.get_basename (uri));
+                    detailed_message = _("The file needs %s but only %s are left.").printf (
+                        format_size (download.total_size), format_size (free_space));
+                }
+                else
+                    assert_not_reached ();
+                Sokoke.message_dialog (Gtk.MessageType.ERROR, message, detailed_message, false);
+                return false;
+            }
+            return true;
+        }
+    }
+}
index 9766485fc2836bc7d5f82e03c9430d1a901283ed..808d34c26987421864c66ee3c9ceb09fbf879822 100644 (file)
@@ -2270,8 +2270,7 @@ midori_view_download_uri (MidoriView*        view,
     WebKitDownload* download = webkit_download_new (request);
     gboolean handled;
     g_object_unref (request);
-    g_object_set_data (G_OBJECT (download), "midori-download-type",
-                       GINT_TO_POINTER (type));
+    midori_download_set_type (download, type);
     g_signal_emit (view, signals[DOWNLOAD_REQUESTED], 0, download, &handled);
 }
 
@@ -3185,9 +3184,7 @@ webkit_web_view_download_requested_cb (GtkWidget*      web_view,
     gchar* content_type;
     gchar* description;
     WebKitWebFrame* web_frame;
-    gchar* mime_type;
     WebKitWebDataSource* datasource;
-    WebKitNetworkRequest* request;
     GString* details;
     GIcon* icon;
     GtkWidget* image;
@@ -3205,18 +3202,8 @@ webkit_web_view_download_requested_cb (GtkWidget*      web_view,
     dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
         _("Open or download file from %s"), hostname);
     g_free (hostname);
-    mime_type = g_object_get_data (G_OBJECT (view), "download-mime-type");
-    request = webkit_download_get_network_request (download);
-    if (mime_type != NULL)
-        content_type = g_content_type_from_mime_type (mime_type);
-    else
-        content_type = NULL;
-    if (!content_type)
-        content_type = g_content_type_guess (
-            webkit_download_get_suggested_filename (download), NULL, 0, NULL);
-    if (!content_type)
-        content_type = g_content_type_from_mime_type ("application/octet-stream");
-    mime_type = g_content_type_get_mime_type (content_type);
+    content_type = midori_download_get_content_type (download,
+        g_object_get_data (G_OBJECT (view), "download-mime-type"));
     description = g_content_type_get_description (content_type);
     icon = g_content_type_get_icon (content_type);
     g_themed_icon_append_name (G_THEMED_ICON (icon), "text-html");
@@ -3224,20 +3211,19 @@ webkit_web_view_download_requested_cb (GtkWidget*      web_view,
     g_object_unref (icon);
     gtk_widget_show (image);
     gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (dialog), image);
-    g_free (content_type);
 
     details = g_string_sized_new (20 * 4);
     g_string_append_printf (details, _("File Name: %s"),
         webkit_download_get_suggested_filename (download));
     g_string_append_c (details, '\n');
 
-    if (g_strrstr (description, mime_type))
-        g_string_append_printf (details, _("File Type: '%s'"), mime_type);
+    if (g_strrstr (description, content_type))
+        g_string_append_printf (details, _("File Type: '%s'"), content_type);
     else
-        g_string_append_printf (details, _("File Type: %s ('%s')"), description, mime_type);
+        g_string_append_printf (details, _("File Type: %s ('%s')"), description, content_type);
     g_string_append_c (details, '\n');
     g_free (description);
-    g_free (mime_type);
+    g_free (content_type);
 
     /* Link Fingerprint */
     /* We look at the original URI because redirection would lose the fragment */
@@ -3252,18 +3238,20 @@ webkit_web_view_download_requested_cb (GtkWidget*      web_view,
         midori_uri_get_fingerprint (original_uri, &fingerprint, &fplabel);
         if (fplabel && fingerprint)
         {
+            WebKitNetworkRequest* request = webkit_download_get_network_request (download);
+
             g_string_append (details, fplabel);
             g_string_append_c (details, ' ');
             g_string_append (details, fingerprint);
             g_string_append_c (details, '\n');
+
+            /* Propagate original URI to make it available when the download finishes */
+            g_object_set_data_full (G_OBJECT (request), "midori-original-uri",
+                                    g_strdup (original_uri), g_free);
         }
         g_free (fplabel);
         g_free (fingerprint);
 
-        /* Propagate original URI to make it available when the download finishes */
-        g_object_set_data_full (G_OBJECT (request), "midori-original-uri",
-                                g_strdup (original_uri), g_free);
-
     }
 
     if (webkit_download_get_total_size (download) > webkit_download_get_current_size (download))
@@ -3280,8 +3268,7 @@ webkit_web_view_download_requested_cb (GtkWidget*      web_view,
 
     gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), FALSE);
     /* i18n: A file open dialog title, ie. "Open http://fila.com/manual.tgz" */
-    title = g_strdup_printf (_("Open %s"),
-        webkit_network_request_get_uri (request));
+    title = g_strdup_printf (_("Open %s"), webkit_download_get_uri (download));
     gtk_window_set_title (GTK_WINDOW (dialog), title);
     g_free (title);
     screen = gtk_widget_get_screen (dialog);
@@ -3304,7 +3291,7 @@ webkit_web_view_download_requested_cb (GtkWidget*      web_view,
     gtk_widget_destroy (dialog);
     if (response == GTK_RESPONSE_DELETE_EVENT)
         response = MIDORI_DOWNLOAD_CANCEL;
-    g_object_set_data (G_OBJECT (download), "midori-download-type", GINT_TO_POINTER (response));
+    midori_download_set_type (download, response);
 
     g_signal_emit (view, signals[DOWNLOAD_REQUESTED], 0, download, &handled);
     return handled;
@@ -5447,56 +5434,6 @@ midori_view_can_save (MidoriView* view)
     return FALSE;
 }
 
-static gchar*
-midori_view_get_uri_extension (const gchar* uri)
-{
-    gchar* slash;
-    gchar* period;
-    gchar* ext_end;
-
-    /* Find the last slash in the URI and search for the last period
-       *after* the last slash. This is not completely accurate
-       but should cover most (simple) URIs */
-    slash = strrchr (uri, '/');
-    /* Huh, URI without slashes? */
-    if (!slash)
-        return NULL;
-
-    ext_end = period = strrchr (slash, '.');
-    if (!period)
-       return NULL;
-
-    /* Skip the period */
-    ext_end++;
-    /* If *ext_end is 0 here, the URI ended with a period, so skip */
-    if (!*ext_end)
-       return NULL;
-
-    /* Find the end of the extension */
-    while (*ext_end && g_ascii_isalnum (*ext_end))
-        ext_end++;
-
-    return g_strdup (period);
-}
-
-const gchar*
-midori_view_fallback_extension (MidoriView* view,
-                                const gchar* extension)
-{
-    if (extension && *extension)
-        return extension;
-    g_return_val_if_fail (view->mime_type != NULL, "");
-    if (strstr (view->mime_type, "css"))
-        return ".css";
-    if (strstr (view->mime_type, "javascript"))
-        return ".js";
-    if (strstr (view->mime_type, "html"))
-        return ".htm";
-    if (strstr (view->mime_type, "plain"))
-        return ".txt";
-    return "";
-}
-
 /**
  * midori_view_save_source:
  * @view: a #MidoriView
@@ -5531,9 +5468,9 @@ midori_view_save_source (MidoriView* view,
 
     if (!outfile)
     {
-        gchar* extension = midori_view_get_uri_extension (uri);
+        gchar* extension = midori_download_get_extension_for_uri (uri, NULL);
         unique_filename = g_strdup_printf ("%s/%uXXXXXX%s", midori_paths_get_tmp_dir (),
-            g_str_hash (uri), midori_view_fallback_extension (view, extension));
+            g_str_hash (uri), midori_download_fallback_extension (view->mime_type, extension));
         g_free (extension);
         katze_mkdir_with_parents (midori_paths_get_tmp_dir (), 0700);
         fd = g_mkstemp (unique_filename);
index 3d1cbd1fb02d01bde9440794e79ddcee37acd791..8bca3e269dc8063813f30d3701c498b1025fe722 100644 (file)
@@ -1302,85 +1302,6 @@ sokoke_build_thumbnail_path (const gchar* name)
     return path;
 }
 
-gchar*
-midori_download_prepare_tooltip_text (WebKitDownload* download)
-{
-    gdouble* last_time;
-    guint64* last_size;
-    gint hour = 3600, min = 60;
-    gint hours_left, minutes_left, seconds_left;
-    guint64 total_size = webkit_download_get_total_size (download);
-    guint64 current_size  = webkit_download_get_current_size (download);
-    gdouble time_elapsed = webkit_download_get_elapsed_time (download);
-    gdouble time_estimated, time_diff;
-    gchar* current, *total, *download_speed;
-    gchar* hours_str, *minutes_str, *seconds_str;
-    GString* tooltip = g_string_new (NULL);
-
-    time_diff = time_elapsed / current_size;
-    time_estimated = (total_size - current_size) * time_diff;
-
-    hours_left = time_estimated / hour;
-    minutes_left = (time_estimated - (hours_left * hour)) / min;
-    seconds_left = (time_estimated - (hours_left * hour) - (minutes_left * min));
-
-    hours_str = g_strdup_printf (ngettext ("%d hour", "%d hours", hours_left), hours_left);
-    minutes_str = g_strdup_printf (ngettext ("%d minute", "%d minutes", minutes_left), minutes_left);
-    seconds_str = g_strdup_printf (ngettext ("%d second", "%d seconds", seconds_left), seconds_left);
-
-    current = g_format_size (current_size);
-    total = g_format_size (total_size);
-    last_time = g_object_get_data (G_OBJECT (download), "last-time");
-    last_size = g_object_get_data (G_OBJECT (download), "last-size");
-
-    /* i18n: Download tooltip (size): 4KB of 43MB */
-    g_string_append_printf (tooltip, _("%s of %s"), current, total);
-    g_free (current);
-    g_free (total);
-
-    if (time_elapsed != *last_time)
-        download_speed = g_format_size (
-                (current_size - *last_size) / (time_elapsed - *last_time));
-    else
-        /* i18n: Unknown number of bytes, used for transfer rate like ?B/s */
-        download_speed = g_strdup (_("?B"));
-
-    /* i18n: Download tooltip (transfer rate): (130KB/s) */
-    g_string_append_printf (tooltip, _(" (%s/s)"), download_speed);
-    g_free (download_speed);
-
-    if (time_estimated > 0)
-    {
-        gchar* eta = NULL;
-        if (hours_left > 0)
-            eta = g_strdup_printf ("%s, %s", hours_str, minutes_str);
-        else if (minutes_left >= 10)
-            eta = g_strdup_printf ("%s", minutes_str);
-        else if (minutes_left < 10 && minutes_left > 0)
-            eta = g_strdup_printf ("%s, %s", minutes_str, seconds_str);
-        else if (seconds_left > 0)
-            eta = g_strdup_printf ("%s", seconds_str);
-        if (eta != NULL)
-        {
-            /* i18n: Download tooltip (estimated time) : - 1 hour, 5 minutes remaning */
-            g_string_append_printf (tooltip, _(" - %s remaining"), eta);
-            g_free (eta);
-        }
-    }
-
-    g_free (hours_str);
-    g_free (seconds_str);
-    g_free (minutes_str);
-
-    if (time_elapsed - *last_time > 5.0)
-    {
-        *last_time = time_elapsed;
-        *last_size = current_size;
-    }
-
-    return g_string_free (tooltip, FALSE);
-}
-
 static gboolean
 sokoke_entry_has_placeholder_text (GtkEntry* entry)
 {
@@ -1452,17 +1373,3 @@ sokoke_search_entry_new (const gchar* placeholder_text)
     return entry;
 }
 
-gchar*
-sokoke_get_download_filename (WebKitDownload* download)
-{
-    /* https://bugs.webkit.org/show_bug.cgi?id=83161 */
-    /* https://d19vezwu8eufl6.cloudfront.net/nlp/slides%2F03-01-FormalizingNB.pdf */
-    gchar* filename = g_strdup (webkit_download_get_suggested_filename (download));
-    #ifdef G_OS_WIN32
-    g_strdelimit (filename, "/\\<>:\"|?*", '_');
-    #else
-    g_strdelimit (filename, "/", '_');
-    #endif
-    return filename;
-}
-
index 754ed2cb71675eb118cb1941be08fb31fe6d3b89..9a25ad648893dd19f2628d08c2850d75f88bed8c 100644 (file)
@@ -161,8 +161,6 @@ sokoke_resolve_hostname                 (const gchar*        hostname);
 gboolean
 sokoke_recursive_fork_protection        (const gchar*         uri,
                                          gboolean             set_uri);
-gchar*
-sokoke_get_download_filename            (WebKitDownload*      download);
 
 typedef struct
 {
@@ -183,9 +181,6 @@ sokoke_widget_copy_clipboard (GtkWidget*   widget,
 gchar*
 sokoke_build_thumbnail_path (const gchar* name);
 
-gchar*
-midori_download_prepare_tooltip_text (WebKitDownload* download);
-
 GtkWidget*
 sokoke_search_entry_new               (const gchar*        placeholder_text);
 
index 44e8873b5765db91951ec9e7c9934beab61917cf..b10953fbd62639ea44d59cc9322923c672ed7d98 100644 (file)
@@ -104,13 +104,10 @@ midori_transfers_button_clear_clicked_cb (GtkToolItem*    toolitem,
     while ((gtk_tree_model_iter_nth_child (model, &iter, NULL, n++)))
     {
         WebKitDownload* download;
-        WebKitDownloadStatus status;
 
         gtk_tree_model_get (model, &iter, 1, &download, -1);
 
-        status = webkit_download_get_status (download);
-        if (status == WEBKIT_DOWNLOAD_STATUS_FINISHED
-            || status == WEBKIT_DOWNLOAD_STATUS_CANCELLED)
+        if (midori_download_is_finished (download))
         {
             gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
             n--; /* Decrement n since we just removed it */
@@ -241,9 +238,21 @@ midori_transfers_treeview_render_icon_cb (GtkTreeViewColumn* column,
                                           GtkTreeIter*       iter,
                                           GtkWidget*         treeview)
 {
-    g_object_set (renderer, "stock-id", STOCK_TRANSFER,
+    WebKitDownload* download;
+    gchar* content_type;
+    GIcon* icon;
+
+    gtk_tree_model_get (model, iter, 1, &download, -1);
+    content_type = midori_download_get_content_type (download, NULL);
+    icon = g_content_type_get_icon (content_type);
+    g_themed_icon_append_name (G_THEMED_ICON (icon), "text-html");
+
+    g_object_set (renderer, "gicon", icon,
                   "stock-size", GTK_ICON_SIZE_DND,
                   "xpad", 1, "ypad", 12, NULL);
+    g_free (content_type);
+    g_object_unref (icon);
+    g_object_unref (download);
 }
 
 static void
@@ -254,34 +263,17 @@ midori_transfers_treeview_render_text_cb (GtkTreeViewColumn* column,
                                           GtkWidget*         treeview)
 {
     WebKitDownload* download;
-    gchar* current;
-    gchar* total;
-    gchar* size_text;
-    gchar* text;
-    gchar* filename;
+    gchar* tooltip;
     gdouble progress;
 
     gtk_tree_model_get (model, iter, 1, &download, -1);
 
-    current = g_format_size (webkit_download_get_current_size (download));
-    total = g_format_size (webkit_download_get_total_size (download));
-    size_text = g_strdup_printf (_("%s of %s"), current, total);
-    g_free (current);
-    g_free (total);
-    filename = sokoke_get_download_filename (download);
-    text = g_strdup_printf ("%s\n%s", filename, size_text);
-    g_free (filename);
-    g_free (size_text);
-    /* Avoid a bug in WebKit */
-    if (webkit_download_get_status (download) != WEBKIT_DOWNLOAD_STATUS_CREATED)
-        progress = webkit_download_get_progress (download);
-    else
-        progress = 0.0;
-    g_object_set (renderer, "text", text,
-                  "ellipsize", PANGO_ELLIPSIZE_END,
+    tooltip = midori_download_get_tooltip (download);
+    progress = midori_download_get_progress (download);
+    g_object_set (renderer, "text", tooltip,
                   "value", (gint)(progress * 100),
                   "xpad", 1, "ypad", 6, NULL);
-    g_free (text);
+    g_free (tooltip);
     g_object_unref (download);
 }
 
@@ -297,17 +289,7 @@ midori_transfers_treeview_render_button_cb (GtkTreeViewColumn* column,
 
     gtk_tree_model_get (model, iter, 1, &download, -1);
 
-    switch (webkit_download_get_status (download))
-    {
-        case WEBKIT_DOWNLOAD_STATUS_STARTED:
-            stock_id = GTK_STOCK_CANCEL;
-            break;
-        case WEBKIT_DOWNLOAD_STATUS_FINISHED:
-            stock_id = GTK_STOCK_OPEN;
-            break;
-        default:
-            stock_id = GTK_STOCK_CLEAR;
-    }
+    stock_id = midori_download_action_stock_id (download);
     g_object_set (renderer, "stock-id", stock_id,
                   "stock-size", GTK_ICON_SIZE_MENU, NULL);
 
@@ -328,25 +310,8 @@ midori_transfers_treeview_row_activated_cb (GtkTreeView*       treeview,
 
         gtk_tree_model_get (model, &iter, 1, &download, -1);
 
-        switch (webkit_download_get_status (download))
-        {
-            case WEBKIT_DOWNLOAD_STATUS_STARTED:
-                webkit_download_cancel (download);
-                break;
-            case WEBKIT_DOWNLOAD_STATUS_FINISHED:
-            {
-                const gchar* uri;
-
-                uri = webkit_download_get_destination_uri (download);
-                sokoke_show_uri (gtk_widget_get_screen (GTK_WIDGET (
-                    treeview)), uri, gtk_get_current_event_time (), NULL);
-                break;
-            }
-            case WEBKIT_DOWNLOAD_STATUS_CANCELLED:
-                /* FIXME: Remove this item from the model */
-            default:
-                break;
-        }
+        if (midori_download_action_clear (download, GTK_WIDGET (treeview), NULL))
+            ; /* FIXME: Remove this item from the model */
         g_object_unref (download);
     }
 }
index 95375830adafcc1257b0b5c2792c4bc0968c6e81..6f26ccaaf1863505734e95683dfcb3f41475aff0 100644 (file)
@@ -12,6 +12,7 @@ midori/midori-panel.c
 midori/midori-settings.vala
 midori/midori-websettings.c
 midori/midori-view.c
+midori/midori-download.vala
 midori/midori-speeddial.vala
 midori/midori-preferences.c
 midori/midori-searchaction.c
index 5896fa104d1a94e05ce080e5fc398e5df52dc963..76e2c8e0d3b7ab258725e86d50075ce3113f33e3 100644 (file)
@@ -76,17 +76,11 @@ midori_transferbar_download_notify_progress_cb (WebKitDownload* download,
                                                 GtkWidget*      progress)
 {
     gchar* tooltip;
-    gchar* text;
-
     gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress),
-        webkit_download_get_progress (download));
-    tooltip = midori_download_prepare_tooltip_text (download);
-    text = g_strdup_printf ("%s\n%s",
-        gtk_progress_bar_get_text (GTK_PROGRESS_BAR (progress)), tooltip);
-    gtk_widget_set_tooltip_text (progress, text);
-
+        midori_download_get_progress (download));
+    tooltip = midori_download_get_tooltip (download);
+    gtk_widget_set_tooltip_text (progress, tooltip);
     g_free (tooltip);
-    g_free (text);
 }
 
 static void
@@ -95,31 +89,22 @@ midori_transferbar_download_notify_status_cb (WebKitDownload* download,
                                               TransferInfo*   info)
 {
     GtkWidget* button = info->button;
-    GtkWidget* icon;
 
-    switch (webkit_download_get_status (download))
+    const gchar* stock_id = midori_download_action_stock_id (download);
+    GtkWidget* icon = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
+    gtk_button_set_image (GTK_BUTTON (button), icon);
+
+    if (webkit_download_get_status (download) == WEBKIT_DOWNLOAD_STATUS_FINISHED)
     {
-        case WEBKIT_DOWNLOAD_STATUS_FINISHED:
-        {
             MidoriBrowser* browser = midori_browser_get_for_widget (button);
-            MidoriDownloadType type = GPOINTER_TO_INT (
-                g_object_get_data (G_OBJECT (download), "midori-download-type"));
-            WebKitNetworkRequest* request;
-            const gchar* original_uri;
-            GChecksumType checksum_type;
-            gchar* fingerprint;
-            gboolean verified = TRUE;
-
-            icon = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
-            gtk_button_set_image (GTK_BUTTON (button), icon);
+            MidoriDownloadType type = midori_download_get_type (download);
+
             if (type == MIDORI_DOWNLOAD_OPEN)
                 gtk_button_clicked (GTK_BUTTON (button));
 
-            if (1)
             {
                 const gchar* uri = webkit_download_get_destination_uri (download);
-                gchar* path = soup_uri_decode (uri);
-                gchar* filename = g_strrstr (path, "/") + 1;
+                gchar* filename = g_path_get_basename (uri);
                 gchar* msg = g_strdup_printf (
                     _("The file '<b>%s</b>' has been downloaded."), filename);
                 KatzeItem* item = katze_item_new ();
@@ -131,47 +116,12 @@ midori_transferbar_download_notify_status_cb (WebKitDownload* download,
                 midori_browser_update_history (item, "download", "create");
                 item->uri = item->name = NULL;
                 g_object_unref (item);
-                g_free (path);
-            }
-
-            /* Link Fingerprint */
-            request = webkit_download_get_network_request (download);
-            original_uri = g_object_get_data (G_OBJECT (request), "midori-original-uri");
-            if (!original_uri)
-                original_uri = webkit_download_get_uri (download);
-            checksum_type = midori_uri_get_fingerprint (original_uri, &fingerprint, NULL);
-            if (fingerprint != NULL)
-            {
-                gchar* filename = g_filename_from_uri (
-                    webkit_download_get_destination_uri (download), NULL, NULL);
-                gchar* contents;
-                gsize length;
-                gboolean y = g_file_get_contents (filename, &contents, &length, NULL);
-                gchar* checksum = g_compute_checksum_for_data (checksum_type,
-                    (guchar*)contents, length);
                 g_free (filename);
-                g_free (contents);
-                /* Checksums are case-insensitive */
-                if (!y || g_ascii_strcasecmp (fingerprint, checksum) != 0)
-                    verified = FALSE;
-                g_free (checksum);
             }
-            g_free (fingerprint);
-            if (verified)
+
+            if (!midori_download_has_wrong_checksum (download))
                  gtk_recent_manager_add_item (gtk_recent_manager_get_default (),
                     webkit_download_get_destination_uri (download));
-            else
-                gtk_image_set_from_stock (GTK_IMAGE (icon),
-                    GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
-            break;
-        }
-        case WEBKIT_DOWNLOAD_STATUS_CANCELLED:
-        case WEBKIT_DOWNLOAD_STATUS_ERROR:
-            icon = gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU);
-            gtk_button_set_image (GTK_BUTTON (button), icon);
-            break;
-        default:
-            break;
     }
 }
 
@@ -180,37 +130,8 @@ midori_transferbar_download_button_clicked_cb (GtkWidget*    button,
                                                TransferInfo* info)
 {
     WebKitDownload* download = info->download;
-
-    switch (webkit_download_get_status (download))
-    {
-        case WEBKIT_DOWNLOAD_STATUS_STARTED:
-            webkit_download_cancel (download);
-            break;
-        case WEBKIT_DOWNLOAD_STATUS_FINISHED:
-        {
-            const gchar* uri = webkit_download_get_destination_uri (download);
-            GtkWidget* icon = gtk_button_get_image (GTK_BUTTON (button));
-            gchar* stock_id;
-            gtk_image_get_stock (GTK_IMAGE (icon), &stock_id, NULL);
-            if (g_str_equal (stock_id, GTK_STOCK_DIALOG_WARNING))
-            {
-                sokoke_message_dialog (GTK_MESSAGE_WARNING,
-                    _("The downloaded file is erroneous."),
-                    _("The checksum provided with the link did not match. " \
-                      "This means the file is probably incomplete or was " \
-                      "modified afterwards."),
-                    TRUE);
-            }
-            else if (sokoke_show_uri (gtk_widget_get_screen (button),
-                uri, gtk_get_current_event_time (), NULL))
-                gtk_widget_destroy (button);
-            break;
-        }
-        case WEBKIT_DOWNLOAD_STATUS_CANCELLED:
-            gtk_widget_destroy (button);
-        default:
-            break;
-    }
+    if (midori_download_action_clear (download, button, NULL))
+        gtk_widget_destroy (button);
 }
 
 void
@@ -231,13 +152,9 @@ midori_transferbar_check_size (GtkWidget* statusbar,
     for (list = transferbar->infos; list != NULL; list = g_list_next (list))
     {
       TransferInfo* info = list->data;
-      WebKitDownloadStatus status = webkit_download_get_status (info->download);
-      if (status == WEBKIT_DOWNLOAD_STATUS_ERROR
-       || status == WEBKIT_DOWNLOAD_STATUS_CANCELLED
-       || status == WEBKIT_DOWNLOAD_STATUS_FINISHED)
-      {
+      if (midori_download_is_finished (info->download)
+       || webkit_download_get_status (info->download) == WEBKIT_DOWNLOAD_STATUS_STARTED)
           gtk_widget_destroy (info->button);
-      }
     }
   }
 }
@@ -251,7 +168,7 @@ midori_transferbar_add_download_item (MidoriTransferbar* transferbar,
     GtkToolItem* toolitem;
     GtkWidget* button;
     GtkWidget* progress;
-    const gchar* uri;
+    const gchar* filename;
     gint width;
     TransferInfo* info;
 
@@ -260,29 +177,16 @@ midori_transferbar_add_download_item (MidoriTransferbar* transferbar,
     #if GTK_CHECK_VERSION (3, 0, 0)
     gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR (progress), TRUE);
     #endif
-    gtk_progress_bar_set_ellipsize (GTK_PROGRESS_BAR (progress),
-                                    PANGO_ELLIPSIZE_MIDDLE);
-    if ((uri = webkit_download_get_destination_uri (download)))
-    {
-        gchar* path = soup_uri_decode (uri);
-        gchar* filename = g_strrstr (path, "/") + 1;
-        gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progress), filename);
-        g_free (path);
-    }
-    else
-    {
-        gchar* filename = sokoke_get_download_filename (download);
-        gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progress), filename);
-        g_free (filename);
-    }
+    gtk_progress_bar_set_ellipsize (GTK_PROGRESS_BAR (progress), PANGO_ELLIPSIZE_MIDDLE);
+    filename = g_strrstr (webkit_download_get_destination_uri (download), "/") + 1;
+    gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progress), filename);
     sokoke_widget_get_text_size (progress, "M", &width, NULL);
     gtk_widget_set_size_request (progress, width * 10, 1);
-    /* Avoid a bug in WebKit */
-    if (webkit_download_get_status (download) != WEBKIT_DOWNLOAD_STATUS_CREATED)
-        gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress),
-            webkit_download_get_progress (download));
+    gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress),
+        midori_download_get_progress (download));
     gtk_box_pack_start (GTK_BOX (box), progress, FALSE, FALSE, 0);
-    icon = gtk_image_new_from_stock (GTK_STOCK_CANCEL, GTK_ICON_SIZE_MENU);
+    icon = gtk_image_new_from_stock (
+        midori_download_action_stock_id (download), GTK_ICON_SIZE_MENU);
     button = gtk_button_new ();
     gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
     gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
@@ -322,13 +226,8 @@ midori_transferbar_clear_clicked_cb (GtkWidget*         button,
     for (list = transferbar->infos; list != NULL; list = g_list_next (list))
     {
         TransferInfo* info = list->data;
-        WebKitDownloadStatus status = webkit_download_get_status (info->download);
-        if (status == WEBKIT_DOWNLOAD_STATUS_ERROR
-         || status == WEBKIT_DOWNLOAD_STATUS_CANCELLED
-         || status == WEBKIT_DOWNLOAD_STATUS_FINISHED)
-        {
+        if (midori_download_is_finished (info->download))
             gtk_widget_destroy (info->button);
-        }
     }
 }
 
@@ -359,11 +258,7 @@ midori_transferbar_confirm_delete (MidoriTransferbar* transferbar)
     for (list = transferbar->infos; list != NULL; list = g_list_next (list))
     {
         TransferInfo* info = list->data;
-        WebKitDownloadStatus status = webkit_download_get_status (info->download);
-
-        if (status != WEBKIT_DOWNLOAD_STATUS_FINISHED
-         && status != WEBKIT_DOWNLOAD_STATUS_CANCELLED
-         && status != WEBKIT_DOWNLOAD_STATUS_ERROR)
+        if (!midori_download_is_finished (info->download))
         {
             all_done = FALSE;
             break;