/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * Copyright © 2011 Igalia S.L. * * This file is part of Epiphany. * * Epiphany is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Epiphany 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Epiphany. If not, see . */ #include "config.h" #include "ephy-debug.h" #include "ephy-download.h" #include "ephy-embed.h" #include "ephy-embed-shell.h" #include "ephy-embed-type-builtins.h" #include "ephy-file-chooser.h" #include "ephy-file-helpers.h" #include "ephy-flatpak-utils.h" #include "ephy-prefs.h" #include "ephy-settings.h" #include "ephy-string.h" #include #include #include struct _EphyDownload { GObject parent_instance; WebKitDownload *download; char *content_type; gboolean show_notification; EphyDownloadActionType action; guint32 start_time; gboolean finished; GError *error; GFileMonitor *file_monitor; }; G_DEFINE_TYPE (EphyDownload, ephy_download, G_TYPE_OBJECT) enum { PROP_0, PROP_DOWNLOAD, PROP_DESTINATION, PROP_ACTION, PROP_START_TIME, PROP_CONTENT_TYPE, LAST_PROP }; static GParamSpec *obj_properties[LAST_PROP]; enum { FILENAME_SUGGESTED, ERROR, COMPLETED, MOVED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL]; static void ephy_download_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { EphyDownload *download = EPHY_DOWNLOAD (object); switch (property_id) { case PROP_DOWNLOAD: g_value_set_object (value, ephy_download_get_webkit_download (download)); break; case PROP_DESTINATION: g_value_set_string (value, ephy_download_get_destination_uri (download)); break; case PROP_ACTION: g_value_set_enum (value, ephy_download_get_action (download)); break; case PROP_START_TIME: g_value_set_uint (value, ephy_download_get_start_time (download)); break; case PROP_CONTENT_TYPE: g_value_set_string (value, ephy_download_get_content_type (download)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void ephy_download_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { EphyDownload *download; download = EPHY_DOWNLOAD (object); switch (property_id) { case PROP_DESTINATION: ephy_download_set_destination_uri (download, g_value_get_string (value)); break; case PROP_ACTION: ephy_download_set_action (download, g_value_get_enum (value)); break; case PROP_DOWNLOAD: case PROP_START_TIME: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } /** * ephy_download_get_content_type: * @download: an #EphyDownload * * Gets content-type information for @download. If the server didn't * provide a content type, the destination file is queried. * * Returns: content-type for @download **/ const char * ephy_download_get_content_type (EphyDownload *download) { g_assert (EPHY_IS_DOWNLOAD (download)); return download->content_type; } /* From the old embed/mozilla/MozDownload.cpp */ static const char * file_is_compressed (const char *filename) { int i; static const char * const compression[] = { ".gz", ".bz2", ".Z", ".lz", ".xz", NULL }; for (i = 0; compression[i] != NULL; i++) { if (g_str_has_suffix (filename, compression[i])) return compression[i]; } return NULL; } static const char * parse_extension (const char *filename) { const char *compression; const char *last_separator; compression = file_is_compressed (filename); /* if the file is compressed we might have a double extension */ if (compression != NULL) { int i; static const char * const extensions[] = { "tar", "ps", "xcf", "dvi", "txt", "text", NULL }; for (i = 0; extensions[i] != NULL; i++) { char *suffix; suffix = g_strdup_printf (".%s%s", extensions[i], compression); if (g_str_has_suffix (filename, suffix)) { char *p; p = g_strrstr (filename, suffix); g_free (suffix); return p; } g_free (suffix); } } /* no compression, just look for the last dot in the filename */ last_separator = strrchr (filename, G_DIR_SEPARATOR); return strrchr ((last_separator) ? last_separator : filename, '.'); } static gboolean set_destination_uri_for_suggested_filename (EphyDownload *download, const char *suggested_filename) { char *dest_dir; char *dest_name; char *destination_filename; char *destination_uri; dest_dir = ephy_file_get_downloads_dir (); /* Make sure the download directory exists */ if (g_mkdir_with_parents (dest_dir, 0700) == -1) { g_critical ("Could not create downloads directory \"%s\": %s", dest_dir, strerror (errno)); g_free (dest_dir); return FALSE; } if (suggested_filename != NULL) { dest_name = ephy_sanitize_filename (g_strdup (suggested_filename)); } else { dest_name = ephy_file_tmp_filename (".ephy-download-XXXXXX", NULL); } destination_filename = g_build_filename (dest_dir, dest_name, NULL); g_free (dest_dir); g_free (dest_name); /* Append (n) as needed. */ if (g_file_test (destination_filename, G_FILE_TEST_EXISTS)) { int i = 1; const char *dot_pos; gssize position; char *serial = NULL; GString *tmp_filename; dot_pos = parse_extension (destination_filename); if (dot_pos) position = dot_pos - destination_filename; else position = strlen (destination_filename); tmp_filename = g_string_new (NULL); do { serial = g_strdup_printf ("(%d)", i++); g_string_assign (tmp_filename, destination_filename); g_string_insert (tmp_filename, position, serial); g_free (serial); } while (g_file_test (tmp_filename->str, G_FILE_TEST_EXISTS)); destination_filename = g_strdup (tmp_filename->str); g_string_free (tmp_filename, TRUE); } destination_uri = g_filename_to_uri (destination_filename, NULL, NULL); g_free (destination_filename); g_assert (destination_uri); webkit_download_set_destination (download->download, destination_uri); g_free (destination_uri); return TRUE; } /** * ephy_download_set_destination_uri: * @download: an #EphyDownload * @destination: URI where to save @download * * Sets the destination URI of @download. It must be a proper URI, with a * scheme like file:/// or similar. **/ void ephy_download_set_destination_uri (EphyDownload *download, const char *destination) { g_assert (EPHY_IS_DOWNLOAD (download)); g_assert (destination != NULL); webkit_download_set_destination (download->download, destination); g_object_notify_by_pspec (G_OBJECT (download), obj_properties[PROP_DESTINATION]); } /** * ephy_download_set_action: * @download: an #EphyDownload * @action: #EphyDownloadActionType to execute * * Sets the @action to be executed when ephy_download_do_download_action () is * called on @download or on finish when "Automatically download and open * files" is set. **/ void ephy_download_set_action (EphyDownload *download, EphyDownloadActionType action) { g_assert (EPHY_IS_DOWNLOAD (download)); download->action = action; g_object_notify_by_pspec (G_OBJECT (download), obj_properties[PROP_ACTION]); } /** * ephy_download_get_webkit_download: * @download: an #EphyDownload * * Gets the #WebKitDownload being wrapped by @download. * * Returns: (transfer none): a #WebKitDownload. **/ WebKitDownload * ephy_download_get_webkit_download (EphyDownload *download) { g_assert (EPHY_IS_DOWNLOAD (download)); return download->download; } /** * ephy_download_get_destination_uri: * @download: an #EphyDownload * * Gets the destination URI where the download is being saved. * * Returns: (transfer none): destination URI. **/ const char * ephy_download_get_destination_uri (EphyDownload *download) { g_assert (EPHY_IS_DOWNLOAD (download)); return webkit_download_get_destination (download->download); } /** * ephy_download_get_action: * @download: an #EphyDownload * * Gets the #EphyDownloadActionType that this download will execute when * ephy_download_do_download_action () is called on it. This action is * performed automatically is "Automatically download and open files" is * enabled. * * Returns: the #EphyDownloadActionType to be executed **/ EphyDownloadActionType ephy_download_get_action (EphyDownload *download) { g_assert (EPHY_IS_DOWNLOAD (download)); return download->action; } /** * ephy_download_get_start_time: * @download: an #EphyDownload * * Gets the time (returned by gtk_get_current_event_time ()) when @download was * started. Defaults to 0. * * Returns: the time when @download was started. **/ guint32 ephy_download_get_start_time (EphyDownload *download) { g_assert (EPHY_IS_DOWNLOAD (download)); return download->start_time; } /** * ephy_download_cancel: * @download: an #EphyDownload * * Cancels the wrapped #WebKitDownload. **/ void ephy_download_cancel (EphyDownload *download) { g_assert (EPHY_IS_DOWNLOAD (download)); webkit_download_cancel (download->download); } gboolean ephy_download_is_active (EphyDownload *download) { g_assert (EPHY_IS_DOWNLOAD (download)); return !download->finished; } gboolean ephy_download_succeeded (EphyDownload *download) { g_assert (EPHY_IS_DOWNLOAD (download)); return download->finished && !download->error; } gboolean ephy_download_failed (EphyDownload *download, GError **error) { g_assert (EPHY_IS_DOWNLOAD (download)); if (download->finished && download->error) { if (error) *error = download->error; return TRUE; } return FALSE; } /** * ephy_download_do_download_action: * @download: an #EphyDownload * @action: one of #EphyDownloadActionType * @user_time: GDK timestamp, for focus-stealing prevention * * Executes the given @action for @download, this can be any of * #EphyDownloadActionType. * * Returns: %TRUE if the action was executed succesfully. * **/ gboolean ephy_download_do_download_action (EphyDownload *download, EphyDownloadActionType action, guint32 user_time) { GFile *destination; const char *destination_uri; gboolean ret = FALSE; destination_uri = webkit_download_get_destination (download->download); destination = g_file_new_for_uri (destination_uri); switch ((action ? action : download->action)) { case EPHY_DOWNLOAD_ACTION_BROWSE_TO: LOG ("ephy_download_do_download_action: browse_to"); /* Must not use this action type under flatpak! */ ret = ephy_file_browse_to (destination, user_time, EPHY_FILE_HELPERS_I_UNDERSTAND_I_MUST_NOT_USE_THIS_FUNCTION_UNDER_FLATPAK); break; case EPHY_DOWNLOAD_ACTION_OPEN: LOG ("ephy_download_do_download_action: open"); ret = ephy_file_launch_handler (destination, user_time); if (!ret && !ephy_is_running_inside_flatpak ()) ret = ephy_file_browse_to (destination, user_time, EPHY_FILE_HELPERS_I_UNDERSTAND_I_MUST_NOT_USE_THIS_FUNCTION_UNDER_FLATPAK); break; case EPHY_DOWNLOAD_ACTION_NONE: LOG ("ephy_download_do_download_action: none"); ret = TRUE; break; default: g_assert_not_reached (); } g_object_unref (destination); return ret; } static void ephy_download_dispose (GObject *object) { EphyDownload *download = EPHY_DOWNLOAD (object); LOG ("EphyDownload disposed %p", object); if (download->download) { g_signal_handlers_disconnect_matched (download->download, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, download); g_object_unref (download->download); download->download = NULL; } g_clear_object (&download->file_monitor); g_clear_error (&download->error); g_clear_pointer (&download->content_type, g_free); G_OBJECT_CLASS (ephy_download_parent_class)->dispose (object); } static void ephy_download_class_init (EphyDownloadClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = ephy_download_get_property; object_class->set_property = ephy_download_set_property; object_class->dispose = ephy_download_dispose; /** * EphyDownload::download: * * Internal WebKitDownload. */ obj_properties[PROP_DOWNLOAD] = g_param_spec_object ("download", "Internal WebKitDownload", "The WebKitDownload used internally by EphyDownload", WEBKIT_TYPE_DOWNLOAD, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * EphyDownload::destination: * * The destination URI where to store the download. */ obj_properties[PROP_DESTINATION] = g_param_spec_string ("destination", "Destination", "Destination file URI", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * EphyDownload::action: * * Action to take when the download finishes or when * ephy_download_do_download_action () is called. */ obj_properties[PROP_ACTION] = g_param_spec_enum ("action", "Download action", "Action to take when download finishes", EPHY_TYPE_DOWNLOAD_ACTION_TYPE, EPHY_DOWNLOAD_ACTION_NONE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * EphyDownload::start-time: * * User time when the download started, useful for launching applications * aware of focus stealing. */ obj_properties[PROP_START_TIME] = g_param_spec_uint ("start-time", "Event start time", "Time for focus-stealing prevention.", 0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_CONTENT_TYPE] = g_param_spec_string ("content-type", "Content Type", "The download content type", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, obj_properties); /** * EphyDownload::filename-suggested: * * The ::filename-suggested signal is emitted when we have received the * suggested filename from WebKit. **/ signals[FILENAME_SUGGESTED] = g_signal_new ("filename-suggested", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE); /** * EphyDownload::completed: * * The ::completed signal is emitted when @download has finished downloading. **/ signals[COMPLETED] = g_signal_new ("completed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); /** * EphyDownload::moved: * * The ::moved signal is emitted when a finished @download has been moved (or deleted). **/ signals[MOVED] = g_signal_new ("moved", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); /** * EphyDownload::error: * * The ::error signal wraps the @download ::error signal. **/ signals[ERROR] = g_signal_new ("error", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_POINTER); } static void ephy_download_init (EphyDownload *download) { LOG ("EphyDownload initialising %p", download); download->download = NULL; download->action = EPHY_DOWNLOAD_ACTION_NONE; download->start_time = gtk_get_current_event_time (); download->show_notification = TRUE; } static void download_response_changed_cb (WebKitDownload *wk_download, GParamSpec *spec, EphyDownload *download) { WebKitURIResponse *response; const char *mime_type; response = webkit_download_get_response (download->download); mime_type = webkit_uri_response_get_mime_type (response); if (!mime_type) return; download->content_type = g_content_type_from_mime_type (mime_type); if (download->content_type) g_object_notify_by_pspec (G_OBJECT (download), obj_properties[PROP_CONTENT_TYPE]); } static gboolean download_decide_destination_cb (WebKitDownload *wk_download, const gchar *suggested_filename, EphyDownload *download) { if (webkit_download_get_destination (wk_download)) return TRUE; g_signal_emit (download, signals[FILENAME_SUGGESTED], 0, suggested_filename); if (webkit_download_get_destination (wk_download)) return TRUE; return set_destination_uri_for_suggested_filename (download, suggested_filename); } static void download_created_destination_cb (WebKitDownload *wk_download, const char *destination, EphyDownload *download) { char *filename; char *content_type; if (download->content_type && !g_content_type_is_unknown (download->content_type)) return; /* The server didn't provide a valid content type, let's try to guess it from the * destination filename. We use g_content_type_guess() here instead of g_file_query_info(), * because we are only using the filename to guess the content type, since it doesn't make * sense to sniff the destination URI that will be empty until the download is completed. * We can't use g_file_query_info() with the partial download file either, because it will * always return application/x-partial-download based on the .wkdownload extension. */ filename = g_filename_from_uri (destination, NULL, NULL); if (!filename) return; content_type = g_content_type_guess (filename, NULL, 0, NULL); g_free (filename); if (g_content_type_is_unknown (content_type)) { /* We could try to connect to received-data signal and sniff the contents when we have * enough data written in the file, but I don't think it's worth it. */ g_free (content_type); return; } if (!download->content_type || !g_content_type_equals (download->content_type, content_type)) { g_free (download->content_type); download->content_type = content_type; g_object_notify_by_pspec (G_OBJECT (download), obj_properties[PROP_CONTENT_TYPE]); return; } g_free (content_type); } static void display_download_finished_notification (WebKitDownload *download) { GApplication *application; GtkWindow *toplevel; const char *dest; application = G_APPLICATION (ephy_embed_shell_get_default ()); toplevel = gtk_application_get_active_window (GTK_APPLICATION (application)); dest = webkit_download_get_destination (download); if (!gtk_window_is_active (toplevel) && dest != NULL) { char *filename; char *message; GNotification *notification; filename = g_filename_display_basename (dest); /* Translators: a desktop notification when a download finishes. */ message = g_strdup_printf (_("Finished downloading %s"), filename); /* Translators: the title of the notification. */ notification = g_notification_new (_("Download finished")); g_notification_set_body (notification, message); g_application_send_notification (application, "download-finished", notification); g_free (filename); g_free (message); g_object_unref (notification); } } static void download_file_monitor_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, EphyDownload *download) { /* Skip messages for .wkdownload */ if (strcmp (g_file_get_uri (file), webkit_download_get_destination (download->download)) != 0) return; if (event_type == G_FILE_MONITOR_EVENT_DELETED || event_type == G_FILE_MONITOR_EVENT_MOVED) g_signal_emit (download, signals[MOVED], 0); } static void download_finished_cb (WebKitDownload *wk_download, EphyDownload *download) { g_autoptr (GError) error = NULL; g_autoptr (GFile) file = NULL; download->finished = TRUE; ephy_download_do_download_action (download, download->action, download->start_time); if (download->show_notification) display_download_finished_notification (wk_download); g_signal_emit (download, signals[COMPLETED], 0); file = g_file_new_for_uri (webkit_download_get_destination (wk_download)); download->file_monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, &error); if (!download->file_monitor) g_warning ("Could not add a file monitor for %s, error: %s\n", g_file_get_uri (file), error->message); else g_signal_connect_object (download->file_monitor, "changed", G_CALLBACK (download_file_monitor_changed), download, 0); } static void download_failed_cb (WebKitDownload *wk_download, GError *error, EphyDownload *download) { g_signal_handlers_disconnect_by_func (wk_download, download_finished_cb, download); LOG ("error (%d - %d)! %s", error->code, 0, error->message); download->finished = TRUE; download->error = g_error_copy (error); g_signal_emit (download, signals[ERROR], 0, download->error); } static void filename_suggested_cb (EphyDownload *download, const char *suggested_filename, gpointer user_data) { GApplication *application; GtkWidget *dialog = NULL; GtkWidget *message_area; GtkWidget *box; GtkWindow *toplevel; GtkWidget *type_label; GtkWidget *from_label; GtkWidget *question_label; GtkWidget *filechooser; WebKitDownload *webkit_download; WebKitURIResponse *response; g_autofree gchar *sanitized_filename = NULL; g_autofree gchar *type_text = NULL; g_autofree gchar *from_text = NULL; g_autofree gchar *content_length = NULL; const gchar *content_type; application = G_APPLICATION (ephy_embed_shell_get_default ()); toplevel = gtk_application_get_active_window (GTK_APPLICATION (application)); dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel), GTK_DIALOG_USE_HEADER_BAR | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s", _("Download requested")); gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Download"), GTK_RESPONSE_OK, NULL); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", suggested_filename); message_area = gtk_message_dialog_get_message_area (GTK_MESSAGE_DIALOG (dialog)); webkit_download = ephy_download_get_webkit_download (download); response = webkit_download_get_response (webkit_download); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_box_pack_start (GTK_BOX (message_area), box, TRUE, TRUE, 0); /* Type */ content_length = g_format_size (webkit_uri_response_get_content_length (response)); content_type = ephy_download_get_content_type (download); type_text = g_strdup_printf (_("Type: %s (%s)"), g_content_type_get_description (content_type), content_length); type_label = gtk_label_new (type_text); gtk_widget_set_margin_top (type_label, 12); gtk_box_pack_start (GTK_BOX (box), type_label, TRUE, TRUE, 0); /* From */ from_text = g_strdup_printf (_("From: %s"), ephy_string_get_host_name (webkit_uri_response_get_uri (response))); from_label = gtk_label_new (from_text); gtk_box_pack_start (GTK_BOX (box), from_label, TRUE, TRUE, 0); /* Question */ question_label = gtk_label_new (_("Where do you want to save the file?")); gtk_widget_set_margin_top (question_label, 12); gtk_box_pack_start (GTK_BOX (box), question_label, TRUE, TRUE, 0); /* File Chooser Button */ filechooser = gtk_file_chooser_button_new (_("Save file"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filechooser), g_settings_get_string (EPHY_SETTINGS_WEB, EPHY_PREFS_WEB_LAST_DOWNLOAD_DIRECTORY)); gtk_box_pack_start (GTK_BOX (box), filechooser, TRUE, TRUE, 0); gtk_widget_show_all (box); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { g_autofree gchar *uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (filechooser)); g_autofree gchar *folder = g_filename_from_uri (uri, NULL, NULL); g_autofree gchar *path = g_build_filename (uri, suggested_filename, NULL); ephy_download_set_destination_uri (download, path); webkit_download_set_allow_overwrite (webkit_download, TRUE); ephy_downloads_manager_add_download (ephy_embed_shell_get_downloads_manager (ephy_embed_shell_get_default ()), download); g_settings_set_string (EPHY_SETTINGS_WEB, EPHY_PREFS_WEB_LAST_DOWNLOAD_DIRECTORY, folder); } else { ephy_download_cancel (download); } gtk_widget_destroy (dialog); } EphyDownload * ephy_download_new_internal (WebKitDownload *download) { EphyDownload *ephy_download; g_assert (WEBKIT_IS_DOWNLOAD (download)); ephy_download = g_object_new (EPHY_TYPE_DOWNLOAD, NULL); g_signal_connect_object (download, "notify::response", G_CALLBACK (download_response_changed_cb), ephy_download, 0); g_signal_connect_object (download, "decide-destination", G_CALLBACK (download_decide_destination_cb), ephy_download, 0); g_signal_connect_object (download, "created-destination", G_CALLBACK (download_created_destination_cb), ephy_download, 0); g_signal_connect_object (download, "finished", G_CALLBACK (download_finished_cb), ephy_download, 0); g_signal_connect_object (download, "failed", G_CALLBACK (download_failed_cb), ephy_download, 0); ephy_download->download = g_object_ref (download); g_object_set_data (G_OBJECT (download), "ephy-download-set", GINT_TO_POINTER (TRUE)); return ephy_download; } /** * ephy_download_new: * @download: a #WebKitDownload to wrap * * Wraps @download in an #EphyDownload. * * Returns: an #EphyDownload. **/ EphyDownload * ephy_download_new (WebKitDownload *download) { EphyDownload *ephy_download; ephy_download = ephy_download_new_internal (download); if (!ephy_is_running_inside_flatpak () && g_settings_get_boolean (EPHY_SETTINGS_WEB, EPHY_PREFS_WEB_ASK_ON_DOWNLOAD)) { g_signal_connect (ephy_download, "filename-suggested", G_CALLBACK (filename_suggested_cb), NULL); } return ephy_download; } /** * ephy_download_new_for_uri: * @uri: a source URI from where to download * * Creates an #EphyDownload to download @uri. * * Returns: an #EphyDownload. **/ EphyDownload * ephy_download_new_for_uri (const char *uri) { EphyDownload *ephy_download; WebKitDownload *download; EphyEmbedShell *shell = ephy_embed_shell_get_default (); g_assert (uri != NULL); download = webkit_web_context_download_uri (ephy_embed_shell_get_web_context (shell), uri); ephy_download = ephy_download_new (download); g_object_unref (download); return ephy_download; } EphyDownload * ephy_download_new_for_uri_internal (const char *uri) { EphyDownload *ephy_download; g_autoptr (WebKitDownload) download = NULL; EphyEmbedShell *shell = ephy_embed_shell_get_default (); g_assert (uri != NULL); download = webkit_web_context_download_uri (ephy_embed_shell_get_web_context (shell), uri); ephy_download = ephy_download_new_internal (download); return ephy_download; } void ephy_download_disable_desktop_notification (EphyDownload *download) { g_assert (EPHY_IS_DOWNLOAD (download)); download->show_notification = FALSE; }