diff options
author | Carlos Garcia Campos <cgarcia@igalia.com> | 2012-06-22 17:03:36 +0800 |
---|---|---|
committer | Carlos Garcia Campos <carlosgc@gnome.org> | 2012-06-27 20:16:00 +0800 |
commit | 7e1964acdacd4bdf4e23e85ec733fe9e92688ca6 (patch) | |
tree | 6acf7bf26c7b8ddf0e4a5161122fccc3c2cd46c2 | |
parent | 39931fc51a3a668d04f938fa555bdf9a4abf3056 (diff) | |
download | gsoc2013-epiphany-7e1964acdacd4bdf4e23e85ec733fe9e92688ca6.tar.gz gsoc2013-epiphany-7e1964acdacd4bdf4e23e85ec733fe9e92688ca6.tar.zst gsoc2013-epiphany-7e1964acdacd4bdf4e23e85ec733fe9e92688ca6.zip |
Port downloads to WebKit2
https://bugzilla.gnome.org/show_bug.cgi?id=678612
-rw-r--r-- | embed/ephy-download.c | 186 | ||||
-rw-r--r-- | embed/ephy-embed.c | 4 | ||||
-rw-r--r-- | embed/ephy-web-view.c | 34 | ||||
-rw-r--r-- | lib/widgets/ephy-download-widget.c | 112 | ||||
-rw-r--r-- | src/ephy-shell.c | 31 | ||||
-rw-r--r-- | src/window-commands.c | 41 |
6 files changed, 320 insertions, 88 deletions
diff --git a/embed/ephy-download.c b/embed/ephy-download.c index dcea8edda..158702bc3 100644 --- a/embed/ephy-download.c +++ b/embed/ephy-download.c @@ -153,49 +153,55 @@ char * ephy_download_get_content_type (EphyDownload *download) { #ifdef HAVE_WEBKIT2 - /* TODO: Downloads */ - return NULL; + WebKitURIResponse *response; #else WebKitNetworkResponse *response; SoupMessage *message; +#endif char *content_type = NULL; - - GFile *destination; - GFileInfo *info; GError *error = NULL; - destination = g_file_new_for_uri (download->priv->destination); - info = g_file_query_info (destination, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, - G_FILE_QUERY_INFO_NONE, NULL, &error); - - if (error) { - LOG ("ephy_download_get_content_type: error getting file " - "content-type: %s", error->message); - g_error_free (error); + if (download->priv->destination) { + GFile *destination; + GFileInfo *info; + + destination = g_file_new_for_uri (download->priv->destination); + info = g_file_query_info (destination, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, + G_FILE_QUERY_INFO_NONE, NULL, &error); + if (info) { + content_type = g_strdup (g_file_info_get_content_type (info)); + LOG ("ephy_download_get_content_type: GIO: %s", content_type); + g_object_unref (info); + } else { + LOG ("ephy_download_get_content_type: error getting file " + "content-type: %s", error->message); + g_error_free (error); + } - /* Fallback to Soup */ - response = webkit_download_get_network_response (download->priv->download); - message = webkit_network_response_get_message (response); + g_object_unref (destination); + } - if (message != NULL) - content_type = g_strdup (soup_message_headers_get_content_type (message->response_headers, NULL)); + if (content_type) + return content_type; - LOG ("ephy_download_get_content_type: Soup: %s", content_type); - } else { - content_type = g_strdup (g_file_info_get_content_type (info)); - LOG ("ephy_download_get_content_type: GIO: %s", content_type); - } + /* Fallback to Soup */ +#ifdef HAVE_WEBKIT2 + response = webkit_download_get_response (download->priv->download); + if (response) + content_type = g_strdup (webkit_uri_response_get_mime_type (response)); +#else + response = webkit_download_get_network_response (download->priv->download); + message = webkit_network_response_get_message (response); - if (info) - g_object_unref (info); + if (message != NULL) + content_type = g_strdup (soup_message_headers_get_content_type (message->response_headers, NULL)); +#endif - if (destination) - g_object_unref (destination); + LOG ("ephy_download_get_content_type: Soup: %s", content_type); LOG ("ephy_download_get_content_type: %s", content_type); return content_type; -#endif } @@ -371,9 +377,7 @@ ephy_download_set_destination_uri (EphyDownload *download, priv->destination = g_strdup (destination); -#ifdef HAVE_WEBKIT2 - /* TODO: Downloads */ -#else +#ifndef HAVE_WEBKIT2 webkit_download_set_destination_uri (priv->download, priv->destination); #endif g_object_notify (G_OBJECT (download), "destination"); @@ -606,9 +610,7 @@ ephy_download_start (EphyDownload *download) if (priv->destination == NULL) ephy_download_set_auto_destination (download); -#ifdef HAVE_WEBKIT2 - /* TODO: Downloads */ -#else +#ifndef HAVE_WEBKIT2 webkit_download_start (priv->download); #endif } @@ -647,12 +649,14 @@ ephy_download_do_download_action (EphyDownload *download, const char *destination_uri; EphyDownloadPrivate *priv; gboolean ret = FALSE; -#ifdef HAVE_WEBKIT2 - /* TODO: Downloads */ -#else + priv = download->priv; +#ifdef HAVE_WEBKIT2 + destination_uri = webkit_download_get_destination (priv->download); +#else destination_uri = webkit_download_get_destination_uri (priv->download); +#endif destination = g_file_new_for_uri (destination_uri); switch ((action ? action : priv->action)) { @@ -682,7 +686,7 @@ ephy_download_do_download_action (EphyDownload *download, break; } g_object_unref (destination); -#endif + return ret; } @@ -901,7 +905,58 @@ ephy_download_init (EphyDownload *download) } #ifdef HAVE_WEBKIT2 -/* TODO: Downloads */ +static gboolean +download_decide_destination_cb (WebKitDownload *wk_download, + const gchar *suggested_filename, + EphyDownload *download) +{ + char *dest; + + if (download->priv->destination) { + webkit_download_set_destination (wk_download, download->priv->destination); + return TRUE; + } + + dest = define_destination_uri (download, suggested_filename); + if (!dest) + return FALSE; + + ephy_download_set_destination_uri (download, dest); + webkit_download_set_destination (wk_download, dest); + g_free (dest); + + return TRUE; +} + +static void +download_created_destination_cb (WebKitDownload *wk_download, + const gchar *destination, + EphyDownload *download) +{ + if (download->priv->destination) + return; + + ephy_download_set_destination_uri (download, destination); +} + +static void +download_finished_cb (WebKitDownload *wk_download, + EphyDownload *download) +{ + EphyDownloadPrivate *priv; + + priv = download->priv; + + g_signal_emit_by_name (download, "completed"); + + if (g_settings_get_boolean (EPHY_SETTINGS_MAIN, EPHY_PREFS_AUTO_DOWNLOADS) && + priv->action == EPHY_DOWNLOAD_ACTION_NONE) + ephy_download_do_download_action (download, EPHY_DOWNLOAD_ACTION_AUTO); + else + ephy_download_do_download_action (download, priv->action); + + ephy_embed_shell_remove_download (embed_shell, download); +} #else static void download_status_changed_cb (GObject *object, @@ -932,7 +987,22 @@ download_status_changed_cb (GObject *object, ephy_embed_shell_add_download (embed_shell, download); } } +#endif + +#ifdef HAVE_WEBKIT2 +static void +download_failed_cb (WebKitDownload *wk_download, + GError *error, + EphyDownload *download) +{ + gboolean ret = FALSE; + + g_signal_handlers_disconnect_by_func (wk_download, download_finished_cb, download); + LOG ("error (%d - %d)! %s", error->code, 0, error->message); + g_signal_emit_by_name (download, "error", 0, error->code, error->message, &ret); +} +#else static gboolean download_error_cb (WebKitDownload *download, gint error_code, @@ -980,10 +1050,27 @@ EphyDownload * ephy_download_new_for_download (WebKitDownload *download) { EphyDownload *ephy_download; +#ifdef HAVE_WEBKIT2 + WebKitURIRequest *request; +#endif + + g_return_val_if_fail (WEBKIT_IS_DOWNLOAD (download), NULL); + ephy_download = ephy_download_new (); #ifdef HAVE_WEBKIT2 - /* TODO: Downloads */ + g_signal_connect (download, "decide-destination", + G_CALLBACK (download_decide_destination_cb), + ephy_download); + g_signal_connect (download, "created-destination", + G_CALLBACK (download_created_destination_cb), + ephy_download); + g_signal_connect (download, "finished", + G_CALLBACK (download_finished_cb), + ephy_download); + g_signal_connect (download, "failed", + G_CALLBACK (download_failed_cb), + ephy_download); #else g_signal_connect (download, "notify::status", G_CALLBACK (download_status_changed_cb), @@ -991,11 +1078,21 @@ ephy_download_new_for_download (WebKitDownload *download) g_signal_connect (download, "error", G_CALLBACK (download_error_cb), ephy_download); +#endif ephy_download->priv->download = g_object_ref (download); +#ifdef HAVE_WEBKIT2 + request = webkit_download_get_request (download); + ephy_download->priv->source = g_strdup (webkit_uri_request_get_uri (request)); +#else ephy_download->priv->source = g_strdup (webkit_download_get_uri (download)); #endif +#ifdef HAVE_WEBKIT2 + /* In WebKit2 the download has already started */ + ephy_embed_shell_add_download (embed_shell, ephy_download); +#endif + return ephy_download; } @@ -1012,14 +1109,15 @@ ephy_download_new_for_uri (const char *uri) { EphyDownload *ephy_download; WebKitDownload *download; -#ifdef HAVE_WEBKIT2 - /* TODO: Downloads */ - download = NULL; -#else +#ifndef HAVE_WEBKIT2 WebKitNetworkRequest *request; +#endif g_return_val_if_fail (uri != NULL, NULL); +#ifdef HAVE_WEBKIT2 + download = webkit_web_context_download_uri (webkit_web_context_get_default (), uri); +#else request = webkit_network_request_new (uri); download = webkit_download_new (request); diff --git a/embed/ephy-embed.c b/embed/ephy-embed.c index 8c0fa5363..9a820decf 100644 --- a/embed/ephy-embed.c +++ b/embed/ephy-embed.c @@ -551,9 +551,7 @@ ephy_embed_auto_download_url (EphyEmbed *embed, const char *url) ephy_download_set_action (download, EPHY_DOWNLOAD_ACTION_OPEN); } -#ifdef HAVE_WEBKIT2 -/* TODO: Downloads */ -#else +#ifndef HAVE_WEBKIT2 static gboolean download_requested_cb (WebKitWebView *web_view, WebKitDownload *download, diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c index 83a89bf94..2a21b0b70 100644 --- a/embed/ephy-web-view.c +++ b/embed/ephy-web-view.c @@ -1689,8 +1689,12 @@ decide_policy_cb (WebKitWebView *web_view, { WebKitResponsePolicyDecision *response_decision; WebKitURIResponse *response; + WebKitURIRequest *request; EphyWebViewDocumentType type; + GObject *single; const char *mime_type; + const char *uri; + gboolean handled = FALSE; if (decision_type != WEBKIT_POLICY_DECISION_TYPE_RESPONSE) return FALSE; @@ -1716,27 +1720,25 @@ decide_policy_cb (WebKitWebView *web_view, g_object_notify (G_OBJECT (web_view), "document-type"); } + /* If WebKit can't handle the mime type start the download + process */ + if (webkit_web_view_can_show_mime_type (web_view, mime_type)) + return FALSE; + /* TODO: Check also Content-Disposition header before emitting * handle-content signal. We need API for that in WebKit2. */ - if (!webkit_web_view_can_show_mime_type (web_view, mime_type)) { - GObject *single; - WebKitURIRequest *request; - const char *uri; - gboolean handled = FALSE; + single = ephy_embed_shell_get_embed_single (embed_shell); + request = webkit_response_policy_decision_get_request (response_decision); + uri = webkit_uri_request_get_uri (request); + g_signal_emit_by_name (single, "handle-content", mime_type, uri, &handled); - single = ephy_embed_shell_get_embed_single (embed_shell); - request = webkit_response_policy_decision_get_request (response_decision); - g_signal_emit_by_name (single, "handle-content", mime_type, uri, &handled); - - if (handled) { - webkit_policy_decision_ignore (decision); - - return TRUE; - } - } + if (handled) + webkit_policy_decision_ignore (decision); + else + webkit_policy_decision_download (decision); - return FALSE; + return TRUE; } #else static gboolean diff --git a/lib/widgets/ephy-download-widget.c b/lib/widgets/ephy-download-widget.c index 40f3b96bf..8de9fe3c6 100644 --- a/lib/widgets/ephy-download-widget.c +++ b/lib/widgets/ephy-download-widget.c @@ -46,6 +46,7 @@ struct _EphyDownloadWidgetPrivate { EphyDownload *download; + GtkWidget *text; GtkWidget *remaining; GtkWidget *button; GtkWidget *menu; @@ -88,7 +89,7 @@ get_destination_basename_from_download (EphyDownload *ephy_download) download = ephy_download_get_webkit_download (ephy_download); #ifdef HAVE_WEBKIT2 - dest = NULL; + dest = webkit_download_get_destination (download); #else dest = webkit_download_get_destination_uri (download); #endif @@ -129,17 +130,21 @@ format_interval (gdouble interval) static gdouble get_remaining_time (WebKitDownload *download) { -#ifdef HAVE_WEBKIT2 - /* TODO: Downloads */ - return -1.0; -#else gint64 total, cur; gdouble elapsed_time; gdouble remaining_time; gdouble per_byte_time; +#ifdef HAVE_WEBKIT2 + WebKitURIResponse *response; + + response = webkit_download_get_response (download); + total = webkit_uri_response_get_content_length (response); + cur = webkit_download_get_received_data_length (download); +#else total = webkit_download_get_total_size (download); cur = webkit_download_get_current_size (download); +#endif elapsed_time = webkit_download_get_elapsed_time (download); if (cur <= 0) @@ -149,7 +154,6 @@ get_remaining_time (WebKitDownload *download) remaining_time = per_byte_time * (total - cur); return remaining_time; -#endif } static void @@ -166,9 +170,6 @@ download_clicked_cb (GtkButton *button, gtk_widget_destroy (GTK_WIDGET (widget)); } -#ifdef HAVE_WEBKIT2 -/* TODO: Downloads */ -#else static void update_download_icon (EphyDownloadWidget *widget) { @@ -192,7 +193,11 @@ update_download_label_and_tooltip (EphyDownloadWidget *widget, char *destination; download = ephy_download_get_webkit_download (widget->priv->download); +#ifdef HAVE_WEBKIT2 + destination = g_filename_display_basename (webkit_download_get_destination (download)); +#else destination = g_filename_display_basename (webkit_download_get_destination_uri (download)); +#endif remaining_tooltip = g_markup_printf_escaped ("%s\n%s", destination, download_label); g_free (destination); @@ -205,25 +210,37 @@ update_download_label_and_tooltip (EphyDownloadWidget *widget, static gboolean download_content_length_is_known (WebKitDownload *download) { +#ifdef HAVE_WEBKIT2 + WebKitURIResponse *response; + + response = webkit_download_get_response (download); + return webkit_uri_response_get_content_length (response); +#else WebKitNetworkResponse *response; SoupMessage* message; response = webkit_download_get_network_response (download); message = webkit_network_response_get_message (response); return soup_message_headers_get_content_length (message->response_headers) > 0; +#endif } static void -widget_progress_cb (GObject *object, +widget_progress_cb (WebKitDownload *download, GParamSpec *pspec, EphyDownloadWidget *widget) { - WebKitDownload *download; int progress; char *download_label = NULL; - download = WEBKIT_DOWNLOAD (object); +#ifdef HAVE_WEBKIT2 + if (!webkit_download_get_destination (download)) + return; + + progress = webkit_download_get_estimated_progress (download) * 100; +#else progress = webkit_download_get_progress (download) * 100; +#endif if (progress % 10 == 0) update_download_icon (widget); @@ -243,7 +260,11 @@ widget_progress_cb (GObject *object, gint64 current_size; /* Unknown content length, show received bytes instead. */ +#ifdef HAVE_WEBKIT2 + current_size = webkit_download_get_received_data_length (download); +#else current_size = webkit_download_get_current_size (download); +#endif if (current_size > 0) download_label = g_format_size (current_size); } @@ -254,14 +275,36 @@ widget_progress_cb (GObject *object, } } +#ifdef HAVE_WEBKIT2 static void -widget_status_cb (GObject *object, +widget_destination_changed_cb (WebKitDownload *download, + GParamSpec *pspec, + EphyDownloadWidget *widget) +{ + char *dest; + + dest = get_destination_basename_from_download (widget->priv->download); + gtk_label_set_text (GTK_LABEL (widget->priv->text), dest); + g_free (dest); +} + +static void +widget_finished_cb (WebKitDownload *download, + EphyDownloadWidget *widget) +{ + widget->priv->finished = TRUE; + update_download_label_and_tooltip (widget, _("Finished")); + totem_glow_button_set_glow (TOTEM_GLOW_BUTTON (widget->priv->button), TRUE); +} +#else +static void +widget_status_cb (WebKitDownload *download, GParamSpec *pspec, EphyDownloadWidget *widget) { WebKitDownloadStatus status; - status = webkit_download_get_status (WEBKIT_DOWNLOAD (object)); + status = webkit_download_get_status (download); if (status != WEBKIT_DOWNLOAD_STATUS_FINISHED) return; @@ -270,7 +313,24 @@ widget_status_cb (GObject *object, update_download_label_and_tooltip (widget, _("Finished")); totem_glow_button_set_glow (TOTEM_GLOW_BUTTON (widget->priv->button), TRUE); } +#endif + +#ifdef HAVE_WEBKIT2 +static void +widget_failed_cb (WebKitDownload *download, + GError *error, + EphyDownloadWidget *widget) +{ + char *error_msg; + g_signal_handlers_disconnect_by_func (download, widget_progress_cb, widget); + + error_msg = g_strdup_printf (_("Error downloading: %s"), error->message); + gtk_label_set_text (GTK_LABEL (widget->priv->remaining), error_msg); + gtk_widget_set_tooltip_text (GTK_WIDGET (widget), error_msg); + g_free (error_msg); +} +#else static gboolean widget_error_cb (WebKitDownload *download, gint error_code, @@ -322,20 +382,20 @@ download_menu_clicked_cb (GtkWidget *button, GdkEventButton *event, EphyDownloadWidget *widget) { -#ifdef HAVE_WEBKIT2 - /* TODO: Downloads */ -#else GtkWidget *item; GtkWidget *menu; GtkWidget *box; GList *children = NULL; char *basename, *name; - WebKitDownload *download; download = ephy_download_get_webkit_download (widget->priv->download); +#ifdef HAVE_WEBKIT2 + basename = g_filename_display_basename (webkit_download_get_destination (download)); +#else basename = g_filename_display_basename (webkit_download_get_destination_uri (download)); +#endif name = g_uri_unescape_string (basename, NULL); box = gtk_widget_get_parent (button); @@ -377,7 +437,6 @@ download_menu_clicked_cb (GtkWidget *button, gtk_menu_attach_to_widget (GTK_MENU (menu), button, NULL); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event->button, event->time); -#endif } static void @@ -433,7 +492,10 @@ ephy_download_widget_dispose (GObject *object) download = ephy_download_get_webkit_download (widget->priv->download); #ifdef HAVE_WEBKIT2 - /* TODO: Downloads */ + g_signal_handlers_disconnect_by_func (download, widget_progress_cb, widget); + g_signal_handlers_disconnect_by_func (download, widget_destination_changed_cb, widget); + g_signal_handlers_disconnect_by_func (download, widget_finished_cb, widget); + g_signal_handlers_disconnect_by_func (download, widget_failed_cb, widget); #else g_signal_handlers_disconnect_by_func (download, widget_progress_cb, widget); g_signal_handlers_disconnect_by_func (download, widget_status_cb, widget); @@ -574,13 +636,21 @@ ephy_download_widget_new (EphyDownload *ephy_download) gtk_widget_set_tooltip_text (GTK_WIDGET (widget), dest); g_free (dest); + widget->priv->text = text; widget->priv->icon = icon; widget->priv->button = button; widget->priv->remaining = remain; widget->priv->menu = menu; #ifdef HAVE_WEBKIT2 - /* TODO: Downloads */ + g_signal_connect (download, "notify::estimated-progress", + G_CALLBACK (widget_progress_cb), widget); + g_signal_connect (download, "notify::destination", + G_CALLBACK (widget_destination_changed_cb), widget); + g_signal_connect (download, "finished", + G_CALLBACK (widget_finished_cb), widget); + g_signal_connect (download, "failed", + G_CALLBACK (widget_failed_cb), widget); #else g_signal_connect (download, "notify::progress", G_CALLBACK (widget_progress_cb), widget); diff --git a/src/ephy-shell.c b/src/ephy-shell.c index 07a646eb3..56c524dd3 100644 --- a/src/ephy-shell.c +++ b/src/ephy-shell.c @@ -544,6 +544,31 @@ impl_get_embed_single (EphyEmbedShell *embed_shell) return embed_single; } +#ifdef HAVE_WEBKIT2 +static void +download_started_cb (WebKitWebContext *web_context, + WebKitDownload *download, + EphyShell *shell) +{ + EphyDownload *ed; + EphySession *session; + EphyWindow *window; + + /* Is download locked down? */ + if (g_settings_get_boolean (EPHY_SETTINGS_LOCKDOWN, + EPHY_PREFS_LOCKDOWN_SAVE_TO_DISK)) { + webkit_download_cancel (download); + return; + } + + session = EPHY_SESSION (ephy_shell_get_session (shell)); + window = ephy_session_get_active_window (session); + + ed = ephy_download_new_for_download (download); + ephy_download_set_window (ed, GTK_WIDGET (window)); +} +#endif + static void ephy_shell_init (EphyShell *shell) { @@ -556,6 +581,12 @@ ephy_shell_init (EphyShell *shell) ephy_shell = shell; g_object_add_weak_pointer (G_OBJECT (ephy_shell), (gpointer *)ptr); + +#ifdef HAVE_WEBKIT2 + g_signal_connect (webkit_web_context_get_default (), "download-started", + G_CALLBACK (download_started_cb), + shell); +#endif } static void diff --git a/src/window-commands.c b/src/window-commands.c index 39432bd18..3a0c43b6f 100644 --- a/src/window-commands.c +++ b/src/window-commands.c @@ -380,7 +380,26 @@ take_page_snapshot_and_set_image (EphyApplicationDialogData *data) } #ifdef HAVE_WEBKIT2 -/* TODO: Downloads */ +static void +download_finished_cb (WebKitDownload *download, + EphyApplicationDialogData *data) +{ + char *filename; + + filename = g_filename_from_uri (webkit_download_get_destination (download), NULL, NULL); + gtk_image_set_from_file (GTK_IMAGE (data->image), filename); + g_free (filename); +} + +static void +download_failed_cb (WebKitDownload *download, + GError *error, + EphyApplicationDialogData *data) +{ + g_signal_handlers_disconnect_by_func (download, download_finished_cb, data); + /* Something happened, default to a page snapshot. */ + take_page_snapshot_and_set_image (data); +} #else static void download_status_changed_cb (WebKitDownload *download, @@ -412,25 +431,39 @@ download_status_changed_cb (WebKitDownload *download, static void download_icon_and_set_image (EphyApplicationDialogData *data) { -#ifdef HAVE_WEBKIT2 - /* TODO: Downloads */ -#else +#ifndef HAVE_WEBKIT2 WebKitNetworkRequest *request; +#endif WebKitDownload *download; char *destination, *destination_uri, *tmp_filename; +#ifdef HAVE_WEBKIT2 + download = webkit_web_context_download_uri (webkit_web_context_get_default (), + data->icon_href); +#else request = webkit_network_request_new (data->icon_href); download = webkit_download_new (request); g_object_unref (request); +#endif tmp_filename = ephy_file_tmp_filename ("ephy-download-XXXXXX", NULL); destination = g_build_filename (ephy_file_tmp_dir (), tmp_filename, NULL); destination_uri = g_filename_to_uri (destination, NULL, NULL); +#ifdef HAVE_WEBKIT2 + webkit_download_set_destination (download, destination_uri); +#else webkit_download_set_destination_uri (download, destination_uri); +#endif g_free (destination); g_free (destination_uri); g_free (tmp_filename); +#ifdef HAVE_WEBKIT2 + g_signal_connect (download, "finished", + G_CALLBACK (download_finished_cb), data); + g_signal_connect (download, "failed", + G_CALLBACK (download_failed_cb), data); +#else g_signal_connect (download, "notify::status", G_CALLBACK (download_status_changed_cb), data); |