[epiphany/downloads: 1/13] ephy-download: add the new EphyDownload object



commit d7ee7921dc55043cfaa7939543ea2220430f1ede
Author: Diego Escalante Urrelo <descalante igalia com>
Date:   Tue Jan 18 11:10:11 2011 -0500

    ephy-download: add the new EphyDownload object
    
    EphyDownload is a wrapper object around WebKitDownload that handles common
    behavior in downloads: auto-destination, default action for the MIME type.
    
    It can be used to wrap a WebKitDownload coming from a WebKitView or to download
    a url: ephy_download_new_for_uri and ephy_download_new_for_download are
    provided.
    
    Its lifetime is not automagic like EphyEmbedPersist, so you have to unref it
    when you no longer need it.
    
    This new object replaces EphyEmbedPersist and enables us to use a single
    codepath for downloads in all Epiphany.
    
    Bug #618443

 embed/Makefile.am        |    2 +
 embed/ephy-download.c    |  936 ++++++++++++++++++++++++++++++++++++++++++++++
 embed/ephy-download.h    |  115 ++++++
 embed/ephy-embed-shell.c |   93 +++++
 embed/ephy-embed-shell.h |   12 +
 lib/ephy-marshal.list    |    1 +
 po/POTFILES.in           |    1 +
 src/Makefile.am          |    2 +
 src/epiphany.h.in        |    1 +
 tests/Makefile.am        |    4 +
 tests/ephy-download.c    |  207 ++++++++++
 11 files changed, 1374 insertions(+), 0 deletions(-)
---
diff --git a/embed/Makefile.am b/embed/Makefile.am
index 5138043..fdd5f11 100644
--- a/embed/Makefile.am
+++ b/embed/Makefile.am
@@ -16,6 +16,7 @@ NOINST_H_FILES = \
 INST_H_FILES = \
 	ephy-adblock.h			\
 	ephy-adblock-manager.h		\
+	ephy-download.h			\
 	ephy-embed.h			\
 	ephy-embed-container.h          \
 	ephy-embed-event.h		\
@@ -37,6 +38,7 @@ libephyembed_la_SOURCES = \
 	ephy-adblock.c			\
 	ephy-adblock-manager.c		\
 	downloader-view.c		\
+	ephy-download.c			\
 	ephy-embed.c			\
 	ephy-embed-container.c          \
 	ephy-embed-dialog.c		\
diff --git a/embed/ephy-download.c b/embed/ephy-download.c
new file mode 100644
index 0000000..8e71de2
--- /dev/null
+++ b/embed/ephy-download.c
@@ -0,0 +1,936 @@
+/* vim: set sw=2 ts=2 sts=2 et: */
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * ephy-download.c
+ * This file is part of Epiphany
+ *
+ * Copyright © 2011 - Igalia S.L.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#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-helpers.h"
+#include "ephy-marshal.h"
+#include "ephy-prefs.h"
+#include "ephy-settings.h"
+
+#include <errno.h>
+#include <glib/gi18n.h>
+#include <string.h>
+#include <webkit/webkit.h>
+
+G_DEFINE_TYPE (EphyDownload, ephy_download, G_TYPE_OBJECT)
+
+#define EPHY_DOWNLOAD_GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), EPHY_TYPE_DOWNLOAD, EphyDownloadPrivate))
+
+struct _EphyDownloadPrivate
+{
+  WebKitDownload *download;
+
+  char *destination;
+  char *source;
+
+  EphyDownloadActionType action;
+  guint32 start_time;
+
+  EphyEmbed *embed;
+  GtkWidget *widget;
+};
+
+enum
+{
+  PROP_0,
+  PROP_DOWNLOAD,
+
+  PROP_DESTINATION,
+  PROP_SOURCE,
+
+  PROP_ACTION,
+  PROP_START_TIME,
+
+  PROP_EMBED,
+  PROP_WIDGET
+};
+
+static void
+ephy_download_get_property (GObject    *object,
+                            guint       property_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  EphyDownload *download;
+  EphyDownloadPrivate *priv;
+
+  download = EPHY_DOWNLOAD (object);
+  priv = download->priv;
+
+  switch (property_id) {
+    case PROP_WIDGET:
+      g_value_set_object (value, priv->widget);
+      break;
+    case PROP_EMBED:
+      g_value_set_object (value, priv->embed);
+      break;
+    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_SOURCE:
+      g_value_set_string (value, ephy_download_get_source_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;
+    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_EMBED:
+      ephy_download_set_embed (download, g_value_get_object (value));
+      break;
+    case PROP_WIDGET:
+      ephy_download_set_widget (download, g_value_get_object (value));
+      break;
+    case PROP_DOWNLOAD:
+    case PROP_SOURCE:
+    case PROP_START_TIME:
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static EphyDownloadActionType
+decide_action_from_mime (EphyDownload *ephy_download)
+{
+  WebKitNetworkResponse *response;
+  SoupMessage *message;
+  char *mime_description = NULL;
+  GAppInfo *helper_app = NULL;
+  EphyMimePermission mime_permission = EPHY_MIME_PERMISSION_SAFE;
+  EphyDownloadActionType action;
+  WebKitDownload *download;
+
+  download = ephy_download_get_webkit_download (ephy_download);
+
+  response = webkit_download_get_network_response (download);
+  message = webkit_network_response_get_message (response);
+
+  if (message) {
+    const char *content_type = soup_message_headers_get_content_type (message->response_headers, NULL);
+
+    if (content_type) {
+      mime_description = g_content_type_get_description (content_type);
+      helper_app = g_app_info_get_default_for_type (content_type, FALSE);
+      mime_permission = ephy_file_check_mime (content_type);
+
+      if (helper_app)
+        action = EPHY_DOWNLOAD_ACTION_OPEN;
+     }
+  }
+
+  if (mime_description == NULL) {
+    mime_description = g_strdup (C_("file type", "Unknown"));
+    action = EPHY_DOWNLOAD_ACTION_BROWSE_TO;
+  }
+
+  /* Sometimes downloads can have a mime_description but a NULL helper_app
+   * in that case action is never changed so DOWNLOAD_ACTION_DOWNLOAD remains
+   * as action value. This is the same response value as Save as...
+   * button, which is wrong for the Download button.
+   */
+  if (helper_app == NULL)
+    action = EPHY_DOWNLOAD_ACTION_BROWSE_TO;
+
+  return action;
+}
+
+void
+ephy_download_do_download_action (EphyDownload *ephy_download,
+                                  EphyDownloadActionType action)
+{
+    GFile *destination;
+    const char *destination_uri;
+    EphyDownloadPrivate *priv;
+
+    priv = ephy_download->priv;
+
+    destination_uri = webkit_download_get_destination_uri (priv->download);
+    destination = g_file_new_for_uri (destination_uri);
+
+    switch ((action ? action : priv->action)) {
+      case EPHY_DOWNLOAD_ACTION_AUTO:
+        LOG ("ephy_download_do_download_action: auto");
+        ephy_download_do_download_action (ephy_download, decide_action_from_mime (ephy_download));
+        break;
+      case EPHY_DOWNLOAD_ACTION_BROWSE_TO:
+        LOG ("ephy_download_do_download_action: browse_to");
+        ephy_file_browse_to (destination, priv->start_time);
+        break;
+      case EPHY_DOWNLOAD_ACTION_OPEN:
+        LOG ("ephy_download_do_download_action: open");
+        ephy_file_launch_handler (NULL, destination, priv->start_time);
+        break;
+      case EPHY_DOWNLOAD_ACTION_NONE:
+        LOG ("ephy_download_do_download_action: none");
+        break;
+      default:
+        g_assert_not_reached ();
+        break;
+    }
+    g_object_unref (destination);
+}
+
+/* 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", 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 char *
+define_destination_uri (EphyDownload *download)
+{
+  char *dest_dir;
+  char *dest_name;
+  char *destination_filename;
+  char *destination_uri;
+  const char *suggested_filename;
+
+  suggested_filename = webkit_download_get_suggested_filename (download->priv->download);
+  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 NULL;
+  }
+
+  if (suggested_filename != NULL) {
+    dest_name = 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);
+
+  return destination_uri;
+}
+
+/**
+ * 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)
+{
+  EphyDownloadPrivate *priv;
+  char *scheme;
+
+  g_return_if_fail (EPHY_IS_DOWNLOAD (download));
+
+  priv = download->priv;
+
+  scheme = g_uri_parse_scheme (destination);
+  g_return_if_fail (scheme != NULL);
+  g_free (scheme);
+
+  priv->destination = g_strdup (destination);
+
+  webkit_download_set_destination_uri (priv->download, priv->destination);
+  g_object_notify (G_OBJECT (download), "destination");
+}
+
+/**
+ * ephy_download_set_auto_destination:
+ * @download: an #EphyDownload
+ *
+ * Tells @download to automatically determine a destination for itself.
+ **/
+void
+ephy_download_set_auto_destination (EphyDownload *download)
+{
+  char *dest;
+
+  g_return_if_fail (EPHY_IS_DOWNLOAD (download));
+
+  dest = define_destination_uri (download);
+  ephy_download_set_destination_uri (download, dest);
+
+  g_free (dest);
+}
+
+/**
+ * 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_return_if_fail (EPHY_IS_DOWNLOAD (download));
+
+  download->priv->action = action;
+  g_object_notify (G_OBJECT (download), "action");
+}
+
+/**
+ * ephy_download_set_embed:
+ * @download: an #EphyDownload
+ * @embed: #EphyEmbed that produced @download
+ *
+ * Sets @embed to be @download's parent, this means that @download will be
+ * shown on @embed's #EphyWindow (where it is contained).
+ **/
+void
+ephy_download_set_embed (EphyDownload *download,
+                         EphyEmbed *embed)
+{
+  g_return_if_fail (EPHY_IS_DOWNLOAD (download));
+
+  download->priv->embed = embed;
+
+  if (embed != NULL)
+    g_object_add_weak_pointer (G_OBJECT (embed), (gpointer *) &download->priv->embed);
+
+  g_object_notify (G_OBJECT (download), "embed");
+}
+
+/**
+ * ephy_download_set_widget:
+ * @download: an #EphyDownload
+ * @widget: a #GtkWidget
+ *
+ * Sets @widget to be associated with @download as its UI.
+ **/
+void
+ephy_download_set_widget (EphyDownload *download,
+                          GtkWidget *widget)
+{
+  g_return_if_fail (EPHY_IS_DOWNLOAD (download));
+
+  download->priv->widget = widget;
+
+  if (widget != NULL)
+    g_object_add_weak_pointer (G_OBJECT (widget), (gpointer *) &download->priv->widget);
+
+  g_object_notify (G_OBJECT (download), "widget");
+}
+
+/**
+ * ephy_download_get_widget:
+ * @download: an #EphyDownload
+ *
+ * Gets the #GtkWidget associated to this download.
+ *
+ * Returns: (transfer none): a #GtkWidget.
+ **/
+GtkWidget *
+ephy_download_get_widget (EphyDownload *download)
+{
+  g_return_val_if_fail (EPHY_IS_DOWNLOAD (download), NULL);
+
+  return download->priv->widget;
+}
+
+/**
+ * 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_return_val_if_fail (EPHY_IS_DOWNLOAD (download), NULL);
+
+  return download->priv->download;
+}
+
+/**
+ * ephy_download_get_embed:
+ * @download: an #EphyDownload
+ *
+ * Gets the #EphyEmbed set as the parent of @download, this can be NULL if no
+ * specific #EphyEmbed generated this download.
+ *
+ * Returns: (transfer none): an #EphyEmbed
+ **/
+EphyEmbed *
+ephy_download_get_embed (EphyDownload *download)
+{
+  g_return_val_if_fail (EPHY_IS_DOWNLOAD (download), NULL);
+
+  return download->priv->embed;
+}
+
+/**
+ * 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_return_val_if_fail (EPHY_IS_DOWNLOAD (download), NULL);
+
+  return download->priv->destination;
+}
+
+/**
+ * ephy_download_get_source_uri:
+ * @download: an #EphyDownload
+ *
+ * Gets the source URI that this download is/will download.
+ *
+ * Returns: (transfer none): source URI.
+ **/
+const char *
+ephy_download_get_source_uri (EphyDownload *download)
+{
+  g_return_val_if_fail (EPHY_IS_DOWNLOAD (download), NULL);
+
+  return download->priv->source;
+}
+
+/**
+ * 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_return_val_if_fail (EPHY_IS_DOWNLOAD (download), EPHY_DOWNLOAD_ACTION_NONE);
+
+  return download->priv->action;
+}
+
+/**
+ * ephy_download_get_start_time:
+ * @download: an #EphyDownload
+ *
+ * Gets the time (returned by gtk_get_current_event_time ()) when @download was
+ * started with ephy_download_start (). Defaults to 0.
+ *
+ * Returns: the time when @download was started.
+ **/
+guint32
+ephy_download_get_start_time (EphyDownload *download)
+{
+  g_return_val_if_fail (EPHY_IS_DOWNLOAD (download), 0);
+
+  return download->priv->start_time;
+}
+
+/**
+ * ephy_download_start:
+ * @download: an #EphyDownload
+ *
+ * Starts the wrapped #WebKitDownload.
+ **/
+void
+ephy_download_start (EphyDownload *download)
+{
+  EphyDownloadPrivate *priv;
+
+  g_return_if_fail (EPHY_IS_DOWNLOAD (download));
+
+  priv = download->priv;
+  priv->start_time = gtk_get_current_event_time ();
+
+  if (priv->destination == NULL)
+    ephy_download_set_auto_destination (download);
+
+  webkit_download_start (priv->download);
+}
+
+/**
+ * ephy_download_cancel:
+ * @download: an #EphyDownload
+ *
+ * Cancels the wrapped #WebKitDownload.
+ **/
+void
+ephy_download_cancel (EphyDownload *download)
+{
+  g_return_if_fail (EPHY_IS_DOWNLOAD (download));
+
+  webkit_download_cancel (download->priv->download);
+}
+
+static void
+ephy_download_dispose (GObject *object)
+{
+  EphyDownload *download = EPHY_DOWNLOAD (object);
+  EphyDownloadPrivate *priv;
+
+  LOG ("EphyDownload disposed %p", object);
+
+  priv = download->priv;
+
+  if (priv->download) {
+    if (webkit_download_get_status (priv->download) == WEBKIT_DOWNLOAD_STATUS_STARTED)
+      webkit_download_cancel (priv->download);
+
+    g_object_unref (priv->download);
+    priv->download = NULL;
+  }
+
+  ephy_embed_shell_remove_download (embed_shell, download);
+
+  G_OBJECT_CLASS (ephy_download_parent_class)->dispose (object);
+}
+
+static void
+ephy_download_finalize (GObject *object)
+{
+  EphyDownload *download = EPHY_DOWNLOAD (object);
+  EphyDownloadPrivate *priv;
+
+  priv = download->priv;
+
+  g_free (priv->destination);
+  g_free (priv->source);
+
+  LOG ("EphyDownload finalised %p", object);
+
+  G_OBJECT_CLASS (ephy_download_parent_class)->finalize (object);
+}
+
+static void
+ephy_download_class_init (EphyDownloadClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (EphyDownloadPrivate));
+
+  object_class->get_property = ephy_download_get_property;
+  object_class->set_property = ephy_download_set_property;
+  object_class->dispose = ephy_download_dispose;
+  object_class->finalize = ephy_download_finalize;
+
+  /**
+   * EphyDownload::download:
+   *
+   * Internal WebKitDownload.
+   */
+  g_object_class_install_property (object_class, PROP_DOWNLOAD,
+                                   g_param_spec_object ("download",
+                                                        "Internal WebKitDownload",
+                                                        "The WebKitDownload used internally by EphyDownload",
+                                                        WEBKIT_TYPE_DOWNLOAD,
+                                                        G_PARAM_READABLE |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_NICK |
+                                                        G_PARAM_STATIC_BLURB));
+
+  /**
+   * EphyDownload::destination:
+   *
+   * The destination URI where to store the download.
+   */
+  g_object_class_install_property (object_class, PROP_DESTINATION,
+                                   g_param_spec_string ("destination",
+                                                        "Destination",
+                                                        "Destination file URI",
+                                                        NULL,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_NICK |
+                                                        G_PARAM_STATIC_BLURB));
+  /**
+   * EphyDownload::source:
+   *
+   * Download's origin URI
+   */
+  g_object_class_install_property (object_class, PROP_SOURCE,
+                                   g_param_spec_string ("source",
+                                                        "Source",
+                                                        "Source URI",
+                                                        NULL,
+                                                        G_PARAM_READABLE |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_NICK |
+                                                        G_PARAM_STATIC_BLURB));
+
+  /**
+   * EphyDownload::action:
+   *
+   * Action to take when the download finishes and "Automatically download and
+   * open files" is enabled, or when ephy_download_do_download_action () is
+   * called.
+   */
+  g_object_class_install_property (object_class, 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_NAME |
+                                                      G_PARAM_STATIC_NICK |
+                                                      G_PARAM_STATIC_BLURB));
+
+  /**
+   * EphyDownload::start-time:
+   *
+   * User time when the download started, useful for launching applications
+   * aware of focus stealing.
+   */
+  g_object_class_install_property (object_class, 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_NAME |
+                                                      G_PARAM_STATIC_NICK |
+                                                      G_PARAM_STATIC_BLURB));
+
+  /**
+   * EphyDownload::embed:
+   *
+   * Embed that produced the download, the download will be shown in the window
+   * where this embed is contained.
+   */
+  g_object_class_install_property (object_class, PROP_EMBED,
+                                   g_param_spec_object ("embed",
+                                                        "A EphyEmbed",
+                                                        "Embed that produced this download.",
+                                                        GTK_TYPE_WIDGET,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_NICK |
+                                                        G_PARAM_STATIC_BLURB));
+
+  /**
+   * EphyDownload::widget:
+   *
+   * An EphyDownloadWidget -or any other GtkWidget- that is representing this
+   * EphyDownload to the user.
+   */
+  g_object_class_install_property (object_class, PROP_WIDGET,
+                                   g_param_spec_object ("widget",
+                                                        "A GtkWidget",
+                                                        "GtkWidget showing this download.",
+                                                        GTK_TYPE_WIDGET,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_NICK |
+                                                        G_PARAM_STATIC_BLURB));
+
+  /**
+   * EphyDownload::completed:
+   *
+   * The ::completed signal is emitted when @download has finished downloading.
+   **/
+  g_signal_new ("completed",
+                G_OBJECT_CLASS_TYPE (object_class),
+                G_SIGNAL_RUN_LAST,
+                G_STRUCT_OFFSET (EphyDownloadClass, completed),
+                NULL, NULL,
+                g_cclosure_marshal_VOID__VOID,
+                G_TYPE_NONE,
+                0);
+  /**
+   * EphyDownload::error:
+   *
+   * The ::error signal wraps the @download ::error signal.
+   **/
+  g_signal_new ("error",
+                G_OBJECT_CLASS_TYPE (object_class),
+                G_SIGNAL_RUN_LAST,
+                G_STRUCT_OFFSET (EphyDownloadClass, error),
+                NULL, NULL,
+                ephy_marshal_BOOLEAN__INT_INT_STRING,
+                G_TYPE_NONE,
+                0);
+}
+
+static void
+ephy_download_init (EphyDownload *download)
+{
+  download->priv = EPHY_DOWNLOAD_GET_PRIVATE (download);
+
+  LOG ("EphyDownload initialising %p", download);
+
+  download->priv->download = NULL;
+  download->priv->destination = NULL;
+
+  download->priv->action = EPHY_DOWNLOAD_ACTION_NONE;
+
+  download->priv->start_time = 0;
+
+  download->priv->embed = NULL;
+  download->priv->widget = NULL;
+}
+
+static void
+download_status_changed_cb (GObject *object,
+                            GParamSpec *pspec,
+                            EphyDownload *download)
+{
+  WebKitDownloadStatus status;
+  EphyDownloadPrivate *priv;
+
+  priv = download->priv;
+
+  status = webkit_download_get_status (priv->download);
+
+  if (status == WEBKIT_DOWNLOAD_STATUS_FINISHED) {
+    g_signal_emit_by_name (download, "completed");
+
+    if (g_settings_get_boolean (EPHY_SETTINGS_MAIN, EPHY_PREFS_AUTO_DOWNLOADS)) {
+      ephy_download_do_download_action (download, EPHY_DOWNLOAD_ACTION_AUTO);
+    } else {
+      ephy_download_do_download_action (download, EPHY_DOWNLOAD_ACTION_NONE);
+    }
+
+    ephy_embed_shell_remove_download (embed_shell, download);
+  } else if (status == WEBKIT_DOWNLOAD_STATUS_CANCELLED ||
+             status == WEBKIT_DOWNLOAD_STATUS_ERROR) {
+  } else if (status == WEBKIT_DOWNLOAD_STATUS_STARTED) {
+    ephy_embed_shell_add_download (embed_shell, download);
+  }
+}
+
+static gboolean
+download_error_cb (WebKitDownload *download,
+                   gint error_code,
+                   gint error_detail,
+                   char *reason,
+                   gpointer user_data)
+{
+  EphyDownload *ephy_download;
+  gboolean ret = FALSE;
+
+  ephy_download = EPHY_DOWNLOAD (user_data);
+
+  LOG ("error (%d - %d)! %s", error_code, error_detail, reason);
+  g_signal_emit_by_name (ephy_download, "error",
+                         error_code, error_detail, reason, &ret);
+
+  return ret;
+}
+
+/**
+ * ephy_download_new:
+ *
+ * Creates a new #EphyDownload. You can use ephy_download_new_for_download and
+ * ephy_download_new_for_uri as convenience functions to create #EphyDownload
+ * objects.
+ *
+ * Returns: an #EphyDownload.
+ **/
+EphyDownload *
+ephy_download_new (void)
+{
+  return g_object_new (EPHY_TYPE_DOWNLOAD, NULL);
+}
+
+static EphyDownload *
+_ephy_download_new (WebKitDownload *webkit_download, const char *uri)
+{
+  EphyDownload *ephy_download;
+  ephy_download = ephy_download_new ();
+
+  if (webkit_download == NULL) {
+    WebKitNetworkRequest *request;
+
+    request = webkit_network_request_new (uri);
+    webkit_download = webkit_download_new (request);
+
+    g_return_val_if_fail (webkit_download != NULL, NULL);
+    g_object_unref (request);
+  }
+
+  g_signal_connect (webkit_download, "notify::status",
+                    G_CALLBACK (download_status_changed_cb),
+                    ephy_download);
+  g_signal_connect (webkit_download, "error",
+                    G_CALLBACK (download_error_cb),
+                    ephy_download);
+
+  ephy_download->priv->download = g_object_ref (webkit_download);
+  ephy_download->priv->source = g_strdup (webkit_download_get_uri (webkit_download));
+
+  return ephy_download;
+}
+
+/**
+ * ephy_download_new_for_download:
+ * @download: a #WebKitDownload to wrap
+ *
+ * Wraps @download in an #EphyDownload.
+ *
+ * Returns: an #EphyDownload.
+ **/
+EphyDownload *
+ephy_download_new_for_download (WebKitDownload *download)
+{
+  g_return_val_if_fail (WEBKIT_IS_DOWNLOAD (download), NULL);
+
+  return _ephy_download_new (download, NULL);
+}
+
+/**
+ * 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)
+{
+  g_return_val_if_fail (uri != NULL, NULL);
+
+  return _ephy_download_new (NULL, uri);
+}
diff --git a/embed/ephy-download.h b/embed/ephy-download.h
new file mode 100644
index 0000000..6241232
--- /dev/null
+++ b/embed/ephy-download.h
@@ -0,0 +1,115 @@
+/* vim: set sw=2 ts=2 sts=2 et: */
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * ephy-download.h
+ * This file is part of Epiphany
+ *
+ * Copyright © 2011 - Igalia S.L.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#if !defined (__EPHY_EPIPHANY_H_INSIDE__) && !defined (EPIPHANY_COMPILATION)
+#error "Only <epiphany/epiphany.h> can be included directly."
+#endif
+
+#ifndef _EPHY_DOWNLOAD_H
+#define _EPHY_DOWNLOAD_H
+
+#include <glib-object.h>
+#include <webkit/webkit.h>
+
+#include "ephy-embed.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_DOWNLOAD              ephy_download_get_type()
+#define EPHY_DOWNLOAD(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_TYPE_DOWNLOAD, EphyDownload))
+#define EPHY_DOWNLOAD_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_TYPE_DOWNLOAD, EphyDownloadClass))
+#define EPHY_IS_DOWNLOAD(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_TYPE_DOWNLOAD))
+#define EPHY_IS_DOWNLOAD_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), EPHY_TYPE_DOWNLOAD))
+#define EPHY_DOWNLOAD_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_TYPE_DOWNLOAD, EphyDownloadClass))
+
+typedef struct _EphyDownload EphyDownload;
+typedef struct _EphyDownloadClass EphyDownloadClass;
+typedef struct _EphyDownloadPrivate EphyDownloadPrivate;
+
+struct _EphyDownload
+{
+  GObject parent;
+
+  EphyDownloadPrivate *priv;
+};
+
+struct _EphyDownloadClass
+{
+  GObjectClass parent_class;
+
+  void (* completed)  (EphyDownload *download);
+  void (* error)      (EphyDownload *download,
+                       gint error_code,
+                       gint error_detail,
+                       char *reason);
+};
+
+typedef enum
+{
+  EPHY_DOWNLOAD_ACTION_NONE,
+  EPHY_DOWNLOAD_ACTION_AUTO,
+  EPHY_DOWNLOAD_ACTION_BROWSE_TO,
+  EPHY_DOWNLOAD_ACTION_OPEN
+} EphyDownloadActionType;
+
+GType         ephy_download_get_type              (void) G_GNUC_CONST;
+
+EphyDownload *ephy_download_new                   (void);
+EphyDownload *ephy_download_new_for_uri           (const char *uri);
+EphyDownload *ephy_download_new_for_download      (WebKitDownload *download);
+
+
+void          ephy_download_start                 (EphyDownload *download);
+void          ephy_download_pause                 (EphyDownload *download);
+void          ephy_download_cancel                (EphyDownload *download);
+
+void          ephy_download_set_auto_destination  (EphyDownload *download);
+void          ephy_download_set_destination_uri   (EphyDownload *download,
+                                                   const char *destination);
+
+WebKitDownload *ephy_download_get_webkit_download (EphyDownload *download);
+
+const char   *ephy_download_get_destination_uri   (EphyDownload *download);
+const char   *ephy_download_get_source_uri        (EphyDownload *download);
+
+
+guint32       ephy_download_get_start_time        (EphyDownload *download);
+
+EphyEmbed    *ephy_download_get_embed             (EphyDownload *download);
+void          ephy_download_set_embed             (EphyDownload *download,
+                                                   EphyEmbed *embed);
+
+EphyDownloadActionType ephy_download_get_action   (EphyDownload *download);
+void          ephy_download_set_action            (EphyDownload *download,
+                                                   EphyDownloadActionType action);
+void          ephy_download_do_download_action    (EphyDownload *ephy_download,
+                                                   EphyDownloadActionType action);
+
+GtkWidget    *ephy_download_get_widget            (EphyDownload *download);
+void          ephy_download_set_widget            (EphyDownload *download,
+                                                   GtkWidget *widget);
+
+G_END_DECLS
+
+#endif /* _EPHY_DOWNLOAD_H */
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
index 3fcf7ee..6d6d309 100644
--- a/embed/ephy-embed-shell.c
+++ b/embed/ephy-embed-shell.c
@@ -28,6 +28,7 @@
 #include "downloader-view.h"
 #include "ephy-adblock-manager.h"
 #include "ephy-debug.h"
+#include "ephy-download.h"
 #include "ephy-embed-shell.h"
 #include "ephy-embed-single.h"
 #include "ephy-encodings.h"
@@ -51,6 +52,7 @@ struct _EphyEmbedShellPrivate
 {
 	EphyHistory *global_history;
 	DownloaderView *downloader_view;
+	GList *downloads;
 	EphyFaviconCache *favicon_cache;
 	EphyEmbedSingle *embed_single;
 	EphyEncodings *encodings;
@@ -63,6 +65,8 @@ struct _EphyEmbedShellPrivate
 
 enum
 {
+	DOWNLOAD_ADDED,
+	DOWNLOAD_REMOVED,
 	PREPARE_CLOSE,
 	QUIT,
 	LAST_SIGNAL
@@ -128,6 +132,14 @@ ephy_embed_shell_finalize (GObject *object)
 {
 	EphyEmbedShell *shell = EPHY_EMBED_SHELL (object);
 
+	if (shell->priv->downloads != NULL)
+	{
+		LOG ("Destroying downloads list");
+		g_list_foreach (shell->priv->downloads, (GFunc) g_object_unref, NULL);
+		g_list_free (shell->priv->downloads);
+		shell->priv->downloads = NULL;
+	}
+
 	if (shell->priv->global_history)
 	{
 		LOG ("Unref history");
@@ -319,6 +331,8 @@ ephy_embed_shell_init (EphyEmbedShell *shell)
 	/* globally accessible singleton */
 	g_assert (embed_shell == NULL);
 	embed_shell = shell;
+
+	shell->priv->downloads = NULL;
 }
 
 static void
@@ -332,6 +346,40 @@ ephy_embed_shell_class_init (EphyEmbedShellClass *klass)
 	klass->get_embed_single = impl_get_embed_single;
 
 /**
+ * EphyEmbed::download-added:
+ * @shell: the #EphyEmbedShell
+ * @download: the #EphyDownload added
+ *
+ * Emitted when a #EphyDownload has been added to the global watch list of
+ * @shell, via ephy_embed_shell_add_download.
+ **/
+	signals[DOWNLOAD_ADDED] =
+		g_signal_new ("download-added",
+			      EPHY_TYPE_EMBED_SHELL,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EphyEmbedShellClass, download_added),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__OBJECT,
+			      G_TYPE_NONE, 1, EPHY_TYPE_DOWNLOAD);
+
+/**
+ * EphyEmbed::download-removed:
+ * @shell: the #EphyEmbedShell
+ * @download: the #EphyDownload being removed
+ *
+ * Emitted when a #EphyDownload has been removed from the global watch list of
+ * @shell, via ephy_embed_shell_remove_download.
+ **/
+	signals[DOWNLOAD_REMOVED] =
+		g_signal_new ("download-removed",
+			      EPHY_TYPE_EMBED_SHELL,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EphyEmbedShellClass, download_removed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__OBJECT,
+			      G_TYPE_NONE, 1, EPHY_TYPE_DOWNLOAD);
+
+/**
  * EphyEmbed::prepare-close:
  * @shell: the #EphyEmbedShell
  * 
@@ -563,6 +611,51 @@ ephy_embed_shell_get_print_settings (EphyEmbedShell *shell)
 	return priv->print_settings;
 }
 
+/**
+ * ephy_embed_shell_get_downloads:
+ * @shell: the #EphyEmbedShell
+ *
+ * Gets the global #GList object listing active downloads.
+ *
+ * Returns: (transfer none): a #GList object
+ **/
+GList *
+ephy_embed_shell_get_downloads (EphyEmbedShell *shell)
+{
+	EphyEmbedShellPrivate *priv;
+
+	g_return_val_if_fail (EPHY_IS_EMBED_SHELL (shell), NULL);
+	priv = shell->priv;
+
+	return priv->downloads;
+}
+
+void
+ephy_embed_shell_add_download (EphyEmbedShell *shell, EphyDownload *download)
+{
+	EphyEmbedShellPrivate *priv;
+
+	g_return_if_fail (EPHY_IS_EMBED_SHELL (shell));
+
+	priv = shell->priv;
+	priv->downloads = g_list_prepend (priv->downloads, download);
+
+	g_signal_emit_by_name (shell, "download-added", download, NULL);
+}
+
+void
+ephy_embed_shell_remove_download (EphyEmbedShell *shell, EphyDownload *download)
+{
+	EphyEmbedShellPrivate *priv;
+
+	g_return_if_fail (EPHY_IS_EMBED_SHELL (shell));
+
+	priv = shell->priv;
+	priv->downloads = g_list_remove (priv->downloads, download);
+
+	g_signal_emit_by_name (shell, "download-removed", download, NULL);
+}
+
 
 static void
 object_notify_cb (EphyEmbedShell *shell, GObject *object)
diff --git a/embed/ephy-embed-shell.h b/embed/ephy-embed-shell.h
index c58df97..6a62ceb 100644
--- a/embed/ephy-embed-shell.h
+++ b/embed/ephy-embed-shell.h
@@ -28,6 +28,8 @@
 #include <glib-object.h>
 #include <gtk/gtk.h>
 
+#include "ephy-download.h"
+
 G_BEGIN_DECLS
 
 #define EPHY_TYPE_EMBED_SHELL		(ephy_embed_shell_get_type ())
@@ -55,6 +57,9 @@ struct _EphyEmbedShellClass
 {
 	GObjectClass parent_class;
 
+	void	  (* download_added)	(EphyEmbedShell *shell, EphyDownload *download);
+	void	  (* download_removed)	(EphyEmbedShell *shell, EphyDownload *download);
+
 	void	  (* prepare_close)	(EphyEmbedShell *shell);
 
 	/*< private >*/
@@ -91,6 +96,13 @@ void		   ephy_embed_shell_set_print_settings	(EphyEmbedShell *shell,
 		
 GtkPrintSettings  *ephy_embed_shell_get_print_settings	(EphyEmbedShell *shell);
 
+GList		  *ephy_embed_shell_get_downloads	(EphyEmbedShell *shell);
+
+void		   ephy_embed_shell_add_download	(EphyEmbedShell *shell,
+							 EphyDownload *download);
+void		   ephy_embed_shell_remove_download	(EphyEmbedShell *shell,
+							 EphyDownload *download);
+
 /* Private API */
 void	       _ephy_embed_shell_track_object		(EphyEmbedShell *shell,
 							 GObject        *object);
diff --git a/lib/ephy-marshal.list b/lib/ephy-marshal.list
index c3f1865..babe824 100644
--- a/lib/ephy-marshal.list
+++ b/lib/ephy-marshal.list
@@ -1,5 +1,6 @@
 BOOLEAN:BOXED
 BOOLEAN:ENUM,STRING,STRING,STRING
+BOOLEAN:INT,INT,STRING
 BOOLEAN:OBJECT
 BOOLEAN:STRING
 BOOLEAN:STRING,BOOLEAN,BOOLEAN
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4e297e6..5548b40 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -11,6 +11,7 @@ data/org.gnome.epiphany.gschema.xml.in
 [type: gettext/glade] data/glade/prefs-dialog.ui
 [type: gettext/glade] data/glade/print.ui
 embed/downloader-view.c
+embed/ephy-download.c
 embed/ephy-embed.c
 embed/ephy-embed-persist.c
 embed/ephy-embed-shell.c
diff --git a/src/Makefile.am b/src/Makefile.am
index ad6bf9e..ef5f0c3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -264,6 +264,7 @@ MAINTAINERCLEANFILES = $(stamp_files) $(BUILT_SOURCES)
 
 if HAVE_INTROSPECTION
 EPHY_GIR_H_FILES = \
+	$(top_srcdir)/embed/ephy-download.h \
 	$(top_srcdir)/embed/ephy-embed.h \
 	$(top_srcdir)/embed/ephy-embed-container.h \
 	$(top_srcdir)/embed/ephy-embed-event.h \
@@ -294,6 +295,7 @@ EPHY_GIR_H_FILES = \
 	$(NULL)
 
 EPHY_GIR_C_FILES = \
+	$(top_srcdir)/embed/ephy-download.c \
 	$(top_srcdir)/embed/ephy-embed.c \
 	$(top_srcdir)/embed/ephy-embed-container.c \
 	$(top_srcdir)/embed/ephy-embed-event.c \
diff --git a/src/epiphany.h.in b/src/epiphany.h.in
index a722c55..8664c15 100644
--- a/src/epiphany.h.in
+++ b/src/epiphany.h.in
@@ -38,6 +38,7 @@
 #include <epiphany/ephy-bookmarks.h>
 #include <epiphany/ephy-bookmarks-type-builtins.h>
 #include <epiphany/ephy-dialog.h>
+#include <epiphany/ephy-download.h>
 #include <epiphany/ephy-embed-container.h>
 #include <epiphany/ephy-embed-event.h>
 #include <epiphany/ephy-embed.h>
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8cba757..1b5aa15 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,4 +1,5 @@
 noinst_PROGRAMS = \
+	test-ephy-download \
 	test-ephy-embed-persist \
 	test-ephy-embed-single \
 	test-ephy-location-entry \
@@ -33,6 +34,9 @@ LDADD += \
 	$(SEED_LIBS)
 endif
 
+test_ephy_download_SOURCES = \
+	ephy-download.c
+
 test_ephy_embed_persist_SOURCES = \
 	ephy-embed-persist.c
 
diff --git a/tests/ephy-download.c b/tests/ephy-download.c
new file mode 100644
index 0000000..14fe81a
--- /dev/null
+++ b/tests/ephy-download.c
@@ -0,0 +1,207 @@
+/* vim: set sw=2 ts=2 sts=2 et: */
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * ephy-download.c
+ * This file is part of Epiphany
+ *
+ * Copyright © 2011 - Igalia S.L.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+#include "ephy-debug.h"
+#include "ephy-download.h"
+#include "ephy-embed-prefs.h"
+#include "ephy-file-helpers.h"
+#include "ephy-shell.h"
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+#define HTML_STRING "testing-embed-persist"
+SoupURI *base_uri;
+
+static char *
+get_uri_for_path (const char *path)
+{
+  SoupURI *uri;
+  char *uri_string;
+
+  uri = soup_uri_new_with_base (base_uri, path);
+  uri_string = soup_uri_to_string (uri, FALSE);
+  soup_uri_free (uri);
+
+  return uri_string;
+}
+
+static void
+server_callback (SoupServer *server,
+                 SoupMessage *msg,
+                 const char *path,
+                 GHashTable *query,
+                 SoupClientContext *context,
+                 gpointer data)
+{
+  soup_message_set_status (msg, SOUP_STATUS_OK);
+
+  if (g_str_equal (path, "/cancelled"))
+    soup_message_set_status (msg, SOUP_STATUS_CANT_CONNECT);
+
+  soup_message_body_append (msg->response_body, SOUP_MEMORY_STATIC,
+                            HTML_STRING, strlen (HTML_STRING));
+
+  soup_message_body_complete (msg->response_body);
+}
+
+typedef struct {
+  GMainLoop *loop;
+  EphyDownload *download;
+  char *destination;
+  char *source;
+} Fixture;
+
+static void
+fixture_setup (Fixture *fixture, gconstpointer data)
+{
+  char *tmp_filename;
+  char *dest_file;
+
+  tmp_filename = ephy_file_tmp_filename ("ephy-download-XXXXXX", NULL);
+  dest_file = g_build_filename (ephy_file_tmp_dir (), tmp_filename, NULL);
+
+  fixture->source = get_uri_for_path ("/default");
+  fixture->download = ephy_download_new_for_uri (fixture->source);
+  fixture->destination = g_filename_to_uri (dest_file, NULL, NULL);
+  fixture->loop = g_main_loop_new (NULL, TRUE);
+
+  ephy_download_set_destination_uri (fixture->download, fixture->destination);
+
+  g_free (tmp_filename);
+  g_free (dest_file);
+}
+
+static void
+fixture_teardown (Fixture *fixture, gconstpointer data)
+{
+  g_free (fixture->destination);
+  g_free (fixture->source);
+
+  g_object_unref (fixture->download);
+
+  g_main_loop_unref (fixture->loop);
+}
+
+static gboolean
+test_file_was_downloaded (EphyDownload *download)
+{
+  char *filename;
+  gboolean ret;
+
+  filename = g_filename_from_uri (ephy_download_get_destination_uri (download),
+                                  NULL, NULL);
+
+  ret = g_file_test (filename, G_FILE_TEST_EXISTS);
+  g_free (filename);
+
+  return ret;
+}
+
+static void
+completed_cb (EphyDownload *download,
+              Fixture *fixture)
+{
+  g_assert (test_file_was_downloaded (download));
+  g_main_loop_quit (fixture->loop);
+}
+
+static void
+test_ephy_download_new (Fixture *fixture, gconstpointer data)
+{
+  g_assert (EPHY_IS_DOWNLOAD (fixture->download));
+}
+
+static void
+test_ephy_download_new_for_uri (Fixture *fixture, gconstpointer data)
+{
+  EphyDownload *download;
+
+  download = ephy_download_new_for_uri (fixture->source);
+
+  g_assert (EPHY_IS_DOWNLOAD (download));
+
+  g_assert_cmpstr (fixture->source, ==, ephy_download_get_source_uri (download));
+
+  g_signal_connect (G_OBJECT (download), "completed",
+                    G_CALLBACK (completed_cb), fixture);
+
+  g_main_loop_run (fixture->loop);
+}
+
+static void
+test_ephy_download_start (Fixture *fixture, gconstpointer data)
+{
+  g_signal_connect (G_OBJECT (fixture->download), "completed",
+                    G_CALLBACK (completed_cb), fixture);
+
+  g_main_loop_run (fixture->loop);
+}
+
+int
+main (int argc, char *argv[])
+{
+  int ret;
+  SoupServer *server;
+
+  gtk_test_init (&argc, &argv);
+  g_thread_init (NULL);
+
+  ephy_debug_init ();
+  ephy_embed_prefs_init ();
+  _ephy_shell_create_instance ();
+
+  if (!ephy_file_helpers_init (NULL, TRUE, FALSE, NULL)) {
+    g_debug ("Something wrong happened with ephy_file_helpers_init()");
+    return -1;
+  }
+
+  server = soup_server_new (SOUP_SERVER_PORT, 0, NULL);
+  soup_server_run_async (server);
+
+  base_uri = soup_uri_new ("http://127.0.0.1/";);
+  soup_uri_set_port (base_uri, soup_server_get_port (server));
+
+  soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
+
+  g_test_add ("/embed/ephy-download/new",
+              Fixture, NULL, fixture_setup,
+              test_ephy_download_new, fixture_teardown);
+  g_test_add ("/embed/ephy-download/new_for_uri",
+              Fixture, NULL, fixture_setup,
+              test_ephy_download_new_for_uri, fixture_teardown);
+  g_test_add ("/embed/ephy-download/start",
+              Fixture, NULL, fixture_setup,
+              test_ephy_download_start, fixture_teardown);
+
+  ret = g_test_run ();
+
+  g_object_unref (ephy_shell);
+  ephy_file_helpers_shutdown ();
+
+  return ret;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]