/*
 * Copyright (c) 2010-2013 Stefan Bolte <portix@gmx.net>
 *
 * This program 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.
 *
 * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <string.h>
#include "dwb.h"
#include "entry.h"
#include "util.h"
#include "soup.h"
#include "scripts.h"

typedef struct _DwbDownload {
    GtkWidget *event;
    GtkWidget *rlabel;
    GtkWidget *llabel;
    WebKitDownload *download;
    DownloadAction action;
    char *path;
    guint n;
    guint sig_button;
    char *mimetype;
} DwbDownload;
typedef struct _DwbDownloadStatus {
#if _HAS_GTK3 
    gdouble blue, red, green, alpha;
#else
    guint blue, red, green;
#endif
    gint64 time;
    gint64 speedtime;
    gdouble  progress;
    DwbDownload *download;
} DwbDownloadStatus;

#define DWB_DOWNLOAD(X) ((DwbDownload*)((X)->data))

static GList *s_downloads = NULL;
static char *s_lastdir = NULL;
static DownloadAction s_lastaction;

/*  dwb_get_command_from_mimetype(char *mimetype){{{*/
static char *
download_get_command_from_mimetype(char *mimetype) 
{
    char *command = NULL;
    if (mimetype == NULL)
        return NULL;

    for (GList *l = dwb.fc.mimetypes; l; l=l->next) 
    {
        Navigation *n = l->data;
        if (!g_strcmp0(n->first, mimetype)) 
        {
            command = n->second;
            break;
        }
    }
    return command;
}/*}}}*/

static gboolean 
download_spawn_external(const char *uri, const char *filename, WebKitDownload *download) 
{
    char **argv; 
    int argc;
    gboolean ret = true;
    GError *error = NULL;
    char *newcommand = NULL;

    char *command = g_strdup(GET_CHAR("download-external-command"));
    WebKitNetworkRequest *request = webkit_download_get_network_request(download);
    const char *referer = soup_get_header_from_request(request, "Referer");
    const char *user_agent = soup_get_header_from_request(request, "User-Agent");

    char *proxy = GET_CHAR("proxy-url");
    gboolean has_proxy = GET_BOOL("proxy");

    char **envp = g_get_environ();
    envp = g_environ_setenv(envp, "DWB_URI", uri, true);
    envp = g_environ_setenv(envp, "DWB_FILENAME", filename, true);
    envp = g_environ_setenv(envp, "DWB_COOKIES", dwb.files[FILES_COOKIES], true);

    if ( (newcommand = util_string_replace(command, "dwb_uri", uri)) ) 
    {
        g_free(command);
        command = newcommand;
    }
    if ( (newcommand = util_string_replace(command, "dwb_cookies", dwb.files[FILES_COOKIES])) ) 
    {
        g_free(command);
        command = newcommand;
    }
    if ( (newcommand = util_string_replace(command, "dwb_output", filename)) ) 
    {
        g_free(command);
        command = newcommand;
    }
    if (referer != NULL) 
    {
        envp = g_environ_setenv(envp, "DWB_REFERER", referer, true);
    }
    if ( (newcommand = util_string_replace(command, "dwb_referer", referer == NULL ? "" : referer)) ) 
    {
        g_free(command);
        command = newcommand;
    }
    if ( (newcommand = util_string_replace(command, "dwb_proxy", proxy == NULL && has_proxy ? "" : proxy)) ) 
    {
        g_free(command);
        command = newcommand;
    }
    if (user_agent != NULL) 
        envp = g_environ_setenv(envp, "DWB_USER_AGENT", user_agent, true);

    if (dwb.state.mimetype_request)
        envp = g_environ_setenv(envp, "DWB_MIME_TYPE", dwb.state.mimetype_request, true);
    if (proxy != NULL && has_proxy) 
        envp = g_environ_setenv(envp, "DWB_PROXY", proxy, true);
    

    g_shell_parse_argv(command, &argc, &argv, NULL);
    g_free(command);
    if (!g_spawn_async(NULL, argv, envp, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error)) 
    {
        perror(error->message);
        ret = false;
    }
    g_strfreev(argv);
    g_strfreev(envp);
    return ret;
}

/* download_get_download_label(WebKitDownload *) {{{*/
static GList * 
download_get_download_label(WebKitDownload *download) 
{
    for (GList *l = s_downloads; l; l=l->next) 
    {
        DwbDownload *label = l->data;
        if (label->download == download) 
            return l;
    }
    return NULL;
}/*}}}*/

/* download_progress_cb(WebKitDownload *) {{{*/
static void
download_progress_cb(WebKitDownload *download, GParamSpec *p, DwbDownloadStatus *status) 
{
    /* Update at most four times a second */
    gint64 time = g_get_monotonic_time();
    static double speed = 0;
    static guint remaining = 0;
    if (time - status->time > 250000) 
    {
        GList *l = download_get_download_label(download); 
        DwbDownload *label = l->data;
        double elapsed = webkit_download_get_elapsed_time(download);
        double progress = webkit_download_get_progress(download);
        double total_size = (double)webkit_download_get_total_size(download) / 0x100000;

        if (time - status->speedtime > 1000000) 
        {
            speed = ((progress - status->progress)*total_size) * 1000000 / (time - status->speedtime);
            status->speedtime = time;
            status->progress = progress;
            remaining = (guint)(elapsed / progress - elapsed);
        }

        double current_size = (double)webkit_download_get_current_size(download) / 0x100000;
        char buffer[128] = {0};
        const char *format = speed > 1 ? "[%.1fM/s|%d:%02d|%2d%%|%.3f/%.3f]" : "[%3.1fK/s|%d:%02d|%2d%%|%.3f/%.3f]";
        snprintf(buffer, sizeof(buffer), format, speed > 1 ? speed : speed*1024, remaining/60, remaining%60,  (int)(progress*100), current_size,  total_size);
        gtk_label_set_text(GTK_LABEL(label->rlabel), buffer);

#if _HAS_GTK3
        gdouble red, green, blue, alpha;
#else 
        guint red, green, blue;
#endif
        red = ((progress) * dwb.color.download_end.red + (1-progress) * dwb.color.download_start.red);
        green = ((progress) * dwb.color.download_end.green + (1-progress) * dwb.color.download_start.green);
        blue = ((progress) * dwb.color.download_end.blue + (1-progress) * dwb.color.download_start.blue);
#if _HAS_GTK3 
        alpha = ((progress) * dwb.color.download_end.alpha + (1-progress) * dwb.color.download_start.alpha);

        if (blue != status->blue || red != status->red || green != status->green || alpha != status->alpha) {
#else 
        if (blue != status->blue || red != status->red || green != status->green) {
#endif
            DwbColor gradient = { 
                .red = red, 
                .green = green, 
                .blue = blue,
#if _HAS_GTK3 
                .alpha = alpha
#endif
            };
            DWB_WIDGET_OVERRIDE_BACKGROUND(label->event, GTK_STATE_NORMAL, &gradient);
        }
        status->blue  = blue;
        status->red   = red;
        status->green = green;
#if _HAS_GTK3 
        status->alpha = alpha;
#endif
        status->time = time;
    }
}/*}}}*/

static void 
download_finished(DwbDownload *d) 
{
    char buffer[64];
    double elapsed = webkit_download_get_elapsed_time(d->download);
    double total_size = (double)webkit_download_get_total_size(d->download);
    snprintf(buffer, sizeof(buffer), "[%.2f KB/s|%.3f MB]", (total_size / (elapsed*0x400)), total_size / 0x100000);
    gtk_label_set_text(GTK_LABEL(d->rlabel), buffer);
}

/* download_do_spawn(const char *cmommand, const char *path, const char * *mimetype_request) {{{*/
static void 
download_do_spawn(const char *command, const char *path, const char *mimetype) 
{
    GError *error = NULL;
    char **argv;
    int argc;
    char *unescaped;

    if (g_str_has_prefix(path, "file://")) 
        path += 7;

    if (!g_shell_parse_argv(command, &argc, &argv, NULL))
        return;

    argv = g_realloc(argv, (argc+2) * sizeof(char*));

    unescaped = g_uri_unescape_string(path, NULL);

    argv[argc++] = unescaped;
    argv[argc++] = NULL;

    if (! g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error) ) 
    {
        fprintf(stderr, "Couldn't open %s with %s : %s\n", path, command, error->message);
        g_clear_error(&error);
    }
    /* Set mimetype */
    GList *list = NULL;
    if (mimetype && *mimetype) 
    {
        Navigation *n = dwb_navigation_new(mimetype, command);
        if ( (list = g_list_find_custom(dwb.fc.mimetypes, n, (GCompareFunc)util_navigation_compare_first))) 
        {
            g_free(list->data);
            dwb.fc.mimetypes = g_list_delete_link(dwb.fc.mimetypes, list);
        }
        dwb.fc.mimetypes = g_list_prepend(dwb.fc.mimetypes, n);
        util_file_add_navigation(dwb.files[FILES_MIMETYPES], n, true, -1);
    }
    g_strfreev(argv);
}/*}}}*/
/* download_spawn(DwbDownload *) {{{*/
static void 
download_spawn(DwbDownload *dl) 
{
    const char *filename = webkit_download_get_destination_uri(dl->download);
    download_do_spawn(dl->path, filename, dl->mimetype);
}/*}}}*/

gboolean
download_delay(DwbDownload *download) 
{
    gtk_widget_destroy(download->event);
    g_free(download->path);
    g_free(download->mimetype);
    g_free(download);
    if (!s_downloads) 
        gtk_widget_hide(dwb.gui.downloadbar);

    return false;
}

/* download_status_cb(WebKitDownload *) {{{*/
static void
download_status_cb(WebKitDownload *download, GParamSpec *p, DwbDownloadStatus *dstatus) 
{
    WebKitDownloadStatus status = webkit_download_get_status(download);
    gboolean script_handled = false;
    if (EMIT_SCRIPT(DOWNLOAD_STATUS)) 
    {
        /**
         * Emitted when the status of a download handled by dwb changes.
         * @event  downloadStatus
         * @memberOf signals
         * @param {signals~onDownloadStatus} callback 
         *      Callback function that will be called when the signal is emitted
         *
         * */
        /**
         * Callback called when the download status changes
         * @callback signals~onDownloadStatus
         *
         * @param {WebKitDownload} download   The download
         *
         * @returns {Boolean} 
         *      Return true to stop dwb from handling the download when the
         *      download has finished
         * */
        ScriptSignal signal = { .jsobj = NULL, { G_OBJECT(download) }, SCRIPTS_SIG_META(NULL, DOWNLOAD_STATUS, 1) };
        script_handled = scripts_emit(&signal);
    }
    if (status == WEBKIT_DOWNLOAD_STATUS_FINISHED || status == WEBKIT_DOWNLOAD_STATUS_CANCELLED || status == WEBKIT_DOWNLOAD_STATUS_ERROR) 
    {
        GList *list = download_get_download_label(download);
        if (list) 
        {
            DwbDownload *label = list->data;
            if (label->action == DL_ACTION_EXECUTE && status == WEBKIT_DOWNLOAD_STATUS_FINISHED && !script_handled) 
                download_spawn(label);
            
            /* Setting time to 0 will force recomputing size */
            dstatus->time = 0;
            switch (status) 
            {
                case WEBKIT_DOWNLOAD_STATUS_FINISHED: 
                    download_finished(label);
                    break;
                case WEBKIT_DOWNLOAD_STATUS_CANCELLED: 
                    gtk_label_set_text(GTK_LABEL(label->rlabel), "cancelled");
                    break;
                case WEBKIT_DOWNLOAD_STATUS_ERROR: 
                    gtk_label_set_text(GTK_LABEL(label->rlabel), "failed");
                    break;
                default: 
                    break;
            }
            Navigation *n = dwb_navigation_new(webkit_download_get_uri(download), webkit_download_get_destination_uri(download));
            dwb.fc.downloads = g_list_append(dwb.fc.downloads, n);
            g_signal_handler_disconnect(label->event, label->sig_button);
            label->download = NULL;
            g_timeout_add_seconds(dwb.misc.message_delay, (GSourceFunc)download_delay, label);
            s_downloads = g_list_delete_link(s_downloads, list);
        }
        if (dwb.state.mimetype_request) 
        {
            g_free(dwb.state.mimetype_request);
            dwb.state.mimetype_request = NULL;
        }
        g_free(dstatus);
        dwb.state.download_ref_count--;
    }
}/*}}}*/

/* download_button_press_cb(GtkWidget *w, GdkEventButton *e, GList *) {{{*/
static gboolean 
download_button_press_cb(GtkWidget *w, GdkEventButton *e, GList *gl) 
{
  if (e->button == 3 && DWB_DOWNLOAD(gl)->download != NULL) 
      webkit_download_cancel(DWB_DOWNLOAD(gl)->download);
  
  return false;
}/*}}}*/

DwbStatus 
download_cancel(int number) 
{
    if (s_downloads == NULL)
        return STATUS_ERROR;

    if (number <= 0) 
    {
        webkit_download_cancel(DWB_DOWNLOAD(s_downloads)->download);
        return STATUS_OK;
    }
    for (GList *l = s_downloads; l; l=l->next) 
    {
        if ((gint)DWB_DOWNLOAD(l)->n == number) 
        {
            webkit_download_cancel(DWB_DOWNLOAD(l)->download);
            return STATUS_OK;
        }
    }
    return STATUS_ERROR;
}

/* download_add_progress_label (GList *gl, const char *filename) {{{*/
static DwbDownload *
download_add_progress_label(GList *gl, const char *filename, gint length) 
{
    DwbDownload *l = g_malloc(sizeof(DwbDownload));

#if _HAS_GTK3
    GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3);
#else 
    GtkWidget *hbox = gtk_hbox_new(false, 3);
#endif
    l->event = gtk_event_box_new();
    l->rlabel = gtk_label_new("???");
    char *name = g_strdup_printf("%d: %s", length, filename);
    l->llabel = gtk_label_new(name);
    g_free(name);

    gtk_box_pack_start(GTK_BOX(hbox), l->llabel, false, false, 1);
    gtk_box_pack_start(GTK_BOX(hbox), l->rlabel, false, false, 1);

    GtkWidget *alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
    int padding = GET_INT("bars-padding");
    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), padding, padding, padding, padding);
    gtk_container_add(GTK_CONTAINER(alignment), hbox);
    gtk_container_add(GTK_CONTAINER(l->event), alignment);

    gtk_box_pack_start(GTK_BOX(dwb.gui.downloadbar), l->event, false, false, 2);

    gtk_label_set_use_markup(GTK_LABEL(l->llabel), true);
    gtk_label_set_use_markup(GTK_LABEL(l->rlabel), true);
    gtk_misc_set_alignment(GTK_MISC(l->llabel), 0.0, 0.5);
    gtk_misc_set_alignment(GTK_MISC(l->rlabel), 1.0, 0.5);

    DWB_WIDGET_OVERRIDE_COLOR(l->llabel, GTK_STATE_NORMAL, &dwb.color.download_fg);
    DWB_WIDGET_OVERRIDE_COLOR(l->rlabel, GTK_STATE_NORMAL, &dwb.color.download_fg);

    DWB_WIDGET_OVERRIDE_BACKGROUND(l->event, GTK_STATE_NORMAL, &dwb.color.download_bg);

    DWB_WIDGET_OVERRIDE_FONT(l->llabel, dwb.font.fd_active);
    DWB_WIDGET_OVERRIDE_FONT(l->rlabel, dwb.font.fd_active);

    l->download = dwb.state.download;

    gtk_widget_show_all(dwb.gui.downloadbar);
    return l;
}/*}}}*/

/* download_start {{{*/
void 
download_start(const char *path) 
{
    if (path == NULL) 
        path = GET_TEXT();

    char escape_buffer[255];
    char *json = NULL;
    gboolean clean = true;
    char *fullpath = NULL;

    const char *filename = webkit_download_get_suggested_filename(dwb.state.download);
    const char *uri = webkit_download_get_uri(dwb.state.download);

    /* FIXME seems to be a bug in webkit ? */
    WebKitNetworkRequest *request = webkit_download_get_network_request(dwb.state.download);
    dwb.state.download = webkit_download_new(request);

    filename = util_normalize_filename(escape_buffer, filename, sizeof(escape_buffer));

    if (EMIT_SCRIPT(DOWNLOAD_START)) 
    {
        /**
         * Emitted before a download starts, after the user has chosen a path or
         * application
         * @event  downloadStart
         * @memberOf signals
         * @param {signals~onDownloadStart} callback 
         *      Callback function that will be called when the signal is emitted
         *
         * */
        /**
         * Callback called when the download status changes
         * @callback signals~onDownloadStart
         *
         * @param {WebKitDownload} download   The download
         * @param {Object} data   
         * @param {String} data.application 
         *      The application that will be spawned when the download has
         *      finished or <i>null</i> if no application will be spawned.
         * @param {String} data.destinationUri 
         *      The destination uri of the download or <i>null</i> if an
         *      application is spawned when the download has finished
         * @param {String} data.mimeType 
         *      The mimetype of the download
         * @param {String} data.referer 
         *      The referer
         *
         * @returns {Boolean} 
         *      Return true to stop dwb from handling the download 
         * */
        if (dwb.state.dl_action == DL_ACTION_EXECUTE) 
        {
            json = util_create_json(4, 
                    CHAR, "referer", soup_get_header_from_request(webkit_download_get_network_request(dwb.state.download), "Referer"), 
                    CHAR, "mimeType", dwb.state.mimetype_request, 
                    CHAR, "application", path, 
                    CHAR, "destinationUri", NULL);
        }
        else 
        {
            char *p = g_build_filename(path, filename, NULL);
            json = util_create_json(4, 
                    CHAR, "referer", soup_get_header_from_request(webkit_download_get_network_request(dwb.state.download), "Referer"), 
                    CHAR, "mimeType", dwb.state.mimetype_request, 
                    CHAR, "destinationUri", p,
                    CHAR, "application", NULL);
            g_free(p);
        }
        ScriptSignal signal = { .jsobj = NULL, .objects = { G_OBJECT(dwb.state.download) }, SCRIPTS_SIG_META(json, DOWNLOAD_START, 1) };
        if (scripts_emit(&signal)) 
        {
            goto error_out;
        }
    }

    //char *command = NULL;
    char *tmppath = NULL;
    const char *last_slash;
    char path_buffer[PATH_MAX];
    gboolean external = GET_BOOL("download-use-external-program");

    char buffer[PATH_MAX];
    path = util_expand_home(buffer, path, sizeof(buffer));

    if (!filename || !strlen(filename)) 
    {
        filename = "dwb_download";
    }

    /* Handle local files */
    if (g_str_has_prefix(uri, "file://") && g_file_test(uri+7, G_FILE_TEST_EXISTS)) 
    {
        if (dwb.state.dl_action == DL_ACTION_EXECUTE) 
        {
            download_do_spawn(path, uri+7, dwb.state.mimetype_request);
        }
        else 
        {
            GFile *source = g_file_new_for_uri(uri);
            fullpath = g_build_filename(path, filename, NULL);
            GFile *dest = g_file_new_for_path(fullpath);
            g_file_copy_async(source, dest, G_FILE_COPY_OVERWRITE, G_PRIORITY_DEFAULT, NULL, NULL, NULL, NULL, NULL);
            g_object_unref(source);
            g_object_unref(dest);
        }
    }
    /* Remote download; */
    else 
    {
        if (dwb.state.dl_action == DL_ACTION_EXECUTE) 
        {
            char *cache_name = g_build_filename(dwb.files[FILES_CACHEDIR], filename, NULL);
            fullpath = g_strconcat("file://", cache_name, NULL);
            g_free(cache_name);
            s_lastaction = DL_ACTION_EXECUTE;
        }
        else 
        {
            if (!path || *path == '\0') 
            {
                path = g_get_current_dir();
            }
            if (g_file_test(path, G_FILE_TEST_IS_DIR)) 
            {
                fullpath = g_build_filename(path, filename, NULL);
                if (!external) 
                {
                    tmppath = fullpath;
                    fullpath = g_strconcat("file://", tmppath, NULL);
                    g_free(tmppath);
                }
            }
            else 
            {
                filename = strrchr(path, '/');
                if (filename != NULL) 
                    filename++;
                else 
                {
                    dwb_set_error_message(dwb.state.fview, "Invalid path: %s", path);
                    clean = false;
                    goto error_out;
                }
                fullpath = external ? g_strdup(path) : g_strconcat("file://", path, NULL);
                if (g_file_test(path, G_FILE_TEST_IS_DIR) && (last_slash = strrchr(path, '/'))) 
                {
                    g_strlcpy(path_buffer, path, last_slash - path);
                    path = path_buffer;
                }
            }
            s_lastaction = DL_ACTION_DOWNLOAD;
        }

        if (external && dwb.state.dl_action == DL_ACTION_DOWNLOAD) 
        {
            if (!download_spawn_external(uri, fullpath, dwb.state.download) ) 
                dwb_set_error_message(dwb.state.fview, "Cannot spawn download program");
        }
        else 
        {
            webkit_download_set_destination_uri(dwb.state.download, fullpath);
            int n = g_list_length(s_downloads)+1;

            DwbDownload *active = download_add_progress_label(dwb.state.fview, filename, n);
            active->action = dwb.state.dl_action;
            active->path = g_strdup(path);
            active->n = n;
            active->mimetype = dwb.state.mimetype_request != NULL ? g_strdup(dwb.state.mimetype_request) : NULL;

            gtk_widget_show_all(dwb.gui.downloadbar);
            s_downloads = g_list_prepend(s_downloads, active);

            DwbDownloadStatus *s = dwb_malloc(sizeof(DwbDownloadStatus));
            s->blue = s->time = 0;
            s->download = active;
            s->progress = 0;
            s->speedtime = g_get_monotonic_time();

            active->sig_button = g_signal_connect(active->event, "button-press-event", G_CALLBACK(download_button_press_cb), s_downloads);
            g_signal_connect(dwb.state.download, "notify::current-size", G_CALLBACK(download_progress_cb), s);
            g_signal_connect(dwb.state.download, "notify::status", G_CALLBACK(download_status_cb), s);

            webkit_download_start(dwb.state.download);
            dwb.state.download_ref_count++;
        }
        g_free(s_lastdir);
        if (dwb.state.dl_action != DL_ACTION_EXECUTE) 
        {
            s_lastdir = g_strdup(path);
        }
    }

error_out:
    dwb_change_mode(NORMAL_MODE, clean);
    dwb.state.download = NULL;
    g_free(json);
    g_free(fullpath);
}/*}}}*/

/* download_entry_set_directory() {{{*/
static void
download_entry_set_directory() 
{
    dwb_set_normal_message(dwb.state.fview, false, "Downloadpath:");
    char *default_dir = GET_CHAR("download-directory");
    char *current_dir = NULL, *new_dir = NULL;
    if (default_dir != NULL) 
    {
        entry_set_text(default_dir);
        return;
    }
    else if (s_lastdir != NULL) 
    {
        entry_set_text(s_lastdir);
        return;
    }
    else 
        current_dir = g_get_current_dir();

    if (g_file_test(current_dir, G_FILE_TEST_IS_DIR) && current_dir[strlen(current_dir) - 1] != '/') 
    {
        new_dir =  g_strdup_printf("%s/", current_dir);
        entry_set_text(new_dir);
        g_free(new_dir);
    }
    else 
        entry_set_text(current_dir);

    g_free(current_dir);
}/*}}}*/

/* download_entry_set_spawn_command{{{*/
void
download_entry_set_spawn_command(const char *command) 
{
    if (!command && dwb.state.mimetype_request) 
        command = download_get_command_from_mimetype(dwb.state.mimetype_request);

    dwb_set_normal_message(dwb.state.fview, false, "Spawn (%s):", dwb.state.mimetype_request ? dwb.state.mimetype_request : "???");
    entry_set_text(command ? command : "");
}/*}}}*/

/* download_get_path {{{*/
void 
download_get_path(GList *gl, WebKitDownload *d) 
{
    const char *path, *command;
    const char *uri = webkit_download_get_uri(d) + 7;

    if (g_file_test(uri,  G_FILE_TEST_IS_EXECUTABLE)) 
    {
        g_spawn_command_line_async(uri, NULL);
        return;
    }
    dwb.state.download = d;
    path = GET_CHAR("download-directory");
    if (path != NULL && g_file_test(path, G_FILE_TEST_IS_DIR) && GET_BOOL("download-no-confirm")) 
        download_start(path);
    else 
    {
        command = download_get_command_from_mimetype(dwb.state.mimetype_request);
        entry_focus();
        dwb.state.mode = DOWNLOAD_GET_PATH;
        dwb.state.download = d;
        if ( s_lastaction != DL_ACTION_DOWNLOAD && 
                ( command != NULL ||  g_file_test(uri, G_FILE_TEST_EXISTS)) ) 
        {
            dwb.state.dl_action = DL_ACTION_EXECUTE;
            download_entry_set_spawn_command(command);
        }
        else 
            download_entry_set_directory();
    }
}/*}}}*/

/* download_set_execute {{{*/
/* TODO complete path should not be in download.c */
void 
download_set_execute(Arg *arg) 
{
    if (dwb.state.mode == DOWNLOAD_GET_PATH) 
    {
        if (dwb.state.dl_action == DL_ACTION_DOWNLOAD) 
        {
            dwb.state.dl_action = DL_ACTION_EXECUTE;
            download_entry_set_spawn_command(NULL);
        }
        else 
        {
            dwb.state.dl_action = DL_ACTION_DOWNLOAD;
            download_entry_set_directory();
        }
    }
}/*}}}*/
