#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <signal.h>
#include <gtk/gtk.h>
#include <unistd.h>

#include "../../include/string.h"
#include "../../include/fio.h"
#include "../../include/disk.h"
#include "../../include/prochandle.h"

#include "../guiutils.h"
#include "../cdialog.h"
#include "../pdialog.h"
#include "../fb.h"
#include "../progressdialog.h"

#include "../edv_types.h"
#include "../edv_cfg_list.h"
#include "../edv_utils.h"
#include "../lib/endeavour2.h"

#include "downloadcfgio.h"
#include "config.h"

#include "../images/icon_planet_32x32.xpm"

#include "../images/icon_download_file_32x32.xpm"
#include "../images/icon_download_file_48x48.xpm"

#include "../images/pdi_file01_20x20.xpm"
#include "../images/pdi_file02_20x20.xpm"
#include "../images/pdi_file03_20x20.xpm"
#include "../images/pdi_file04_20x20.xpm"
#include "../images/pdi_file05_20x20.xpm"
#include "../images/pdi_file06_20x20.xpm"
#include "../images/pdi_folder_32x32.xpm"
#include "../images/pdi_folderfile_32x32.xpm"


static gulong DownloadCurrentMS(void);

#if 0
static gulong DownloadGetAvgFromTimeBuffer(
	const gulong *buf, const gint nitems
);
#endif

static void DownloadSignalCB(int s);
static gchar *DownloadBrowseTargetPathCB(
	gpointer d, gpointer data, gint prompt_num
);

static gulong DownloadTryGetTotalLength(FILE *fp);
static gint DownloadMonitor(
	edv_context_struct *ctx,
	const gint p, const gulong check_interval_ms,
	const gchar *src, const gchar *tar,
	const gchar *stdout_file,
	const GdkGeometryFlags geometry_flags,
	const GdkRectangle *geometry
);


#define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
#define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
#define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
#define STRDUP(s)       (((s) != NULL) ? g_strdup(s) : NULL)

#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define STRLEN(s)       (((s) != NULL) ? strlen(s) : 0)
#define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : TRUE)


/*
 *      Returns the current time in milliseconds.
 */
static gulong DownloadCurrentMS(void)
{
#ifdef __MSW__
	SYSTEMTIME t;   /* Current time of day structure */

	GetSystemTime(&t);
	return(
	    (gulong)(
		(((((t.wHour * 60.0) + t.wMinute) * 60) + t.wSecond) * 1000) +
		t.wMilliseconds
	    )
	);
#else
	struct timeval tv[1];

	if(gettimeofday(tv, NULL) < 0)
	    return(0l);

	return((gulong)(
	    ((tv->tv_sec % 86400l) * 1000l) + (tv->tv_usec / 1000l)
	));
#endif
}

#if 0
/*
 *	Returns the average value of the specified time buffer.
 *
 *	Note that this average is biased to the last (highest) index
 *	value.
 */
static gulong DownloadGetAvgFromTimeBuffer(
	const gulong *buf, const gint nitems 
)
{
	gint i;
	gulong l;

	if((buf == NULL) || (nitems <= 0))
	    return(0l);

	if(nitems == 1)
	    return(buf[0]);

	l = buf[0];
	for(i = 1; i < nitems; i++)
	    l += buf[i];

	return(l / nitems);
}
#endif


/*
 *      UNIX signal callback.
 */
static void DownloadSignalCB(int s)
{
	switch(s)
	{
	  case SIGINT:
	  case SIGTERM:
	  case SIGSEGV:
	    exit(1);
	    break;
	}
}

/*
 *	Prompt dialog browse target path callback.
 */
static gchar *DownloadBrowseTargetPathCB(
	gpointer d, gpointer data, gint prompt_num
)
{
	gboolean status;
	gint total_ftypes = 0, npaths = 0;
	gchar **paths_list = NULL;       
	fb_type_struct **ftype = NULL, *ftype_rtn = NULL;
	GtkWidget *toplevel = NULL;

	if(FileBrowserIsQuery())
	    return(NULL);

	/* Create the file types list */
	FileBrowserTypeListNew(
	    &ftype, &total_ftypes,
	    "*.*", "All files"
	);

	/* Query the user for path */
	FileBrowserSetTransientFor(toplevel);
	status = FileBrowserGetResponse(
#if defined(PROG_LANGUAGE_SPANISH)
"El Sendero Selecto",
"Selecto",
"Cancele",
#elif defined(PROG_LANGUAGE_FRENCH)
"Choisir le répertoire",
"Choisir",
"Annuler",
#elif defined(PROG_LANGUAGE_GERMAN)
"Erlesener Pfad",
"Erlesen.",
"Heben",
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scegliere Il Sentiero",
"Scegliere",
"Annullare",
#elif defined(PROG_LANGUAGE_DUTCH)
"Uitgezocht Pad",
"Uitgezocht",
"Annuleer",
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Selecione Caminho",
"Selecione",
"Cancelamento",
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Utvalgt Sti",
"Utvalgt",
"Kanseller",
#else
"Select Path",
"Select",
"Cancel",
#endif
	    PDialogGetPromptValue(prompt_num),
	    ftype, total_ftypes,
	    &paths_list, &npaths,
	    &ftype_rtn
	);
	FileBrowserSetTransientFor(NULL);

	/* Delete file types list */
	FileBrowserDeleteTypeList(ftype, total_ftypes);

	/* Reset due to possible file related change */
	FileBrowserReset();

	return((npaths > 0) ? paths_list[0] : NULL);
}

/*
 *	Reads the first 1024 bytes (or less) of the file specified by
 *	fp, searching for the total length header (prefixed by the
 *	string "\nLength:".
 *
 *	This function may return (gulong)-1, indicating that a permanent
 *	error has occured and not to call it anymore.  It normally
 *	returns the total length (or 0 if it was not found).
 */
static gulong DownloadTryGetTotalLength(FILE *fp)
{
	gulong total_length = 0;
	gchar *buf;
	gint buf_len, bytes_read;
	struct stat stat_buf;


	if(fp == NULL)
	    return((gulong)-1);

	if(fstat(fileno(fp), &stat_buf))
	    return((gulong)-1);

	buf_len = (gint)stat_buf.st_size;
	if(buf_len <= 0)
	    return((gulong)-1);

	/* Allocate the read buffer */
	buf = (gchar *)g_malloc((buf_len + 1) * sizeof(gchar));
	if(buf == NULL)
	    return((gulong)-1);

	/* Read the beginning of the file, searching for the content
	 * length "\nLength:" string
	 */
	rewind(fp);
	bytes_read = fread(buf, sizeof(gchar), buf_len, fp);
	if(bytes_read > 0)
	{
	    gchar *s, num_str[80];

	    /* Null terminate buffer */
	    if(bytes_read >= buf_len)
		buf[buf_len - 1] = '\0';
	    else
		buf[bytes_read] = '\0';

	    /* Look for the content length string and that we got the
	     * entire line.
	     */
	    s = strstr(buf, "\nLength:");
	    if((s != NULL) ?
		(strchr(s + 1, '\n') != NULL) : FALSE
	    )
	    {
		/* Found string, now seek past it to the next space
		 * space separated string.
		 */
		while(!ISBLANK(*s) && (*s != '\0'))
		    s++;
		while(ISBLANK(*s))
		    s++;

		/* Now s is positioned at the string we want, it is
		 * assumed to be a number so copy it to num_str
		 */
		strncpy(num_str, s, sizeof(num_str));
		num_str[sizeof(num_str) - 1] = '\0';
		/* Null terminate number string */
		s = num_str;
		while(!ISBLANK(*s) && (*s != '\0'))
		    s++;
		*s = '\0';

		/* Now we need to get rid of the ',' characters (if any)
		 * in the number string.
		 */
		substr(num_str, ",", "");
		total_length = ATOL(num_str);
		/* Number string was 0 or contained no numbers?
		 *
		 * Then set total_length to 1, indicating that although
		 * we got the total length, it was undeciperable
		 * (which can happen if the total length is not given)
		 */
		if(total_length == 0)
		    total_length = (gulong)-1;

	    }	/* Look for the content length string */
	}

	/* Delete the read buffer */
	g_free(buf);

	return(total_length);
#undef buf_len
}


/*
 *	Monitors the download process p.
 *
 *	Returns:
 *
 *	0	Success
 *	-2	Process exited but object not downloaded completely
 *	-3	Object does not exist or unable to download from remote
 *		server (downloaded object will not exist)
 *	-4	User aborted
 */
static gint DownloadMonitor(
	edv_context_struct *ctx,
	const gint p, const gulong check_interval_ms,
	const gchar *src, const gchar *tar,
	const gchar *stdout_file,
	const GdkGeometryFlags geometry_flags,
	const GdkRectangle *geometry
)
{
	FILE *fp;
	gboolean	notified_object_added = FALSE,
			user_abort = FALSE;
	const gchar *cstrptr;
	const gint check_count_max = (gint)(
	    check_interval_ms * 1000l / 20000l
	);
	gint check_count = 0, notify_count = 0;

#if 0
gint time_left_sec_nitems = 0;
gulong time_left_sec_buf[1];
const int time_left_sec_max_items = sizeof(time_left_sec_buf) / sizeof(gulong);
#endif
	gulong	last_length = 0l,
		current_length = 0l,
		total_length = 0l,
		last_millitime = DownloadCurrentMS();
	gchar *title, *message, *p1, *p2, *tar_name;
	guint8        **start_icon_data[3],
			**icon_data[6],
			**end_icon_data[3];
	struct stat stat_buf;

	/* Get just the name of the target */
	cstrptr = strrchr(tar, '/');
	if(cstrptr != NULL)
	    tar_name = STRDUP(cstrptr + 1);
	else
	    tar_name = STRDUP(tar);

	/* Set up icon data */
	start_icon_data[0] = (guint8 **)icon_planet_32x32_xpm;
	start_icon_data[1] = (guint8 **)icon_planet_32x32_xpm;
	start_icon_data[2] = (guint8 **)icon_planet_32x32_xpm;

	icon_data[0] = (guint8 **)pdi_file01_20x20_xpm;
	icon_data[1] = (guint8 **)pdi_file02_20x20_xpm;
	icon_data[2] = (guint8 **)pdi_file03_20x20_xpm;
	icon_data[3] = (guint8 **)pdi_file04_20x20_xpm;
	icon_data[4] = (guint8 **)pdi_file05_20x20_xpm;
	icon_data[5] = (guint8 **)pdi_file06_20x20_xpm;

	end_icon_data[0] = (guint8 **)pdi_folder_32x32_xpm;
	end_icon_data[1] = (guint8 **)pdi_folder_32x32_xpm;
	end_icon_data[2] = (guint8 **)pdi_folderfile_32x32_xpm;

	/* Format title */
	title = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Descargar"
#elif defined(PROG_LANGUAGE_FRENCH)
"Télécharger"
#elif defined(PROG_LANGUAGE_GERMAN)
"Laden"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scaricare"
#elif defined(PROG_LANGUAGE_DUTCH)
"Downloaden"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Download"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Downloading"
#else
"Downloading"
#endif
	    " %s", tar_name
	);

	/* Format the source and target paths for the message, shorten
	 * them so that the message on each line is fully visible
	 */
	p1 = EDVShortenPath(
	    src, EDV_DEF_PROGRESS_BAR_PATH_DISPLAY_MAX - 6
	);
	p2 = EDVShortenPath(
	    tar, EDV_DEF_PROGRESS_BAR_PATH_DISPLAY_MAX - 16
	);
	/* Format the initial message */
	message = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Descargar:\n\
\n\
    %s (conectar...)\n\
\n\
A:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Télécharger:\n\
\n\
    %s (connecter...)\n\
\n\
A:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Laden:\n\
\n\
    %s (verbinden...)\n\
\n\
Zu:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scaricare:\n\
\n\
    %s (collegare...)\n\
\n\
A:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Downloaden:\n\
\n\
    %s (verbinden...)\n\
\n\
Te:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Download:\n\
\n\
    %s (ligar...)\n\
\n\
A:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Downloading:\n\
\n\
    %s (forbinding...)\n\
\n\
Til:\n\
\n\
    %s\n"
#else
"Downloading:\n\
\n\
    %s (connecting...)\n\
\n\
To:\n\
\n\
    %s\n"
#endif
	    , p1, p2
	);

	/* Set the progress dialog's WM icon */
	ProgressDialogSetWMIconData(
	    (const guint8 **)icon_download_file_48x48_xpm
	);

	/* Set the progress dialog's geometry */
	if(geometry != NULL)
	{
	    GtkWidget *w = ProgressDialogGetToplevel();
	    if(w != NULL)
	    {
		gtk_widget_set_uposition(
		    w,
		    (geometry_flags & GDK_GEOMETRY_X) ?
			geometry->x : 0,
		    (geometry_flags & GDK_GEOMETRY_Y) ?
			geometry->y : 0
		);
	    }
	}

	/* Map the progress dialog */
	ProgressDialogMapAnimation(
	    title,
	    message,
#if defined(PROG_LANGUAGE_SPANISH)
"Parada"
#elif defined(PROG_LANGUAGE_FRENCH)
"Arrêt"
#elif defined(PROG_LANGUAGE_GERMAN)
"Halt"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Fermata"
#elif defined(PROG_LANGUAGE_DUTCH)
"Einde"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Parada"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Stans"
#else
"Stop"
#endif
	    , start_icon_data, 3,
	    icon_data, 6,
	    end_icon_data, 3,
	    500l,
	    10000
	);

	g_free(title);
	title = NULL;
	g_free(message);
	message = NULL;


	/* Open the download process' stdout file */
	fp = FOpen(stdout_file, "rb");

	/* While the download process is running... */
	while(TRUE)
	{
	    /* User aborted? */
	    if(ProgressDialogStopCount() > 0)
	    {
		kill(p, SIGINT);
		user_abort = TRUE;
		break;
	    }

#if 1
	    /* Time to check on the download progress? */
	    if(check_count >= check_count_max)
#else
	    /* Time to do some checks (at least every 1 second)? */
	    if(check_count >= 50)
#endif
	    {
		/* Is the download process is done */
		if(!ExecProcessExists(p))
		    break;

		/* Need to get total length? Only call this to try and
		 * get the total length if we have not obtained it yet
		 *
		 * If total_length is non-zero or (gulong)-1 then it
		 * means it has already been obtained or is not
		 * available. In either case we should not try to get
		 * it anymore
		 */
		if(total_length == 0)
		    total_length = DownloadTryGetTotalLength(fp);

		/* Get the stats of the target object */
		if(!stat(tar, &stat_buf))
		{
		    gchar time_left_str[80];
		    gulong	cur_ms, delta_ms,
				time_remaining_sec,
				delta_length, remaining_length;

		    /* Update current length and time lapse between
		     * length checks
		     */
		    last_length = current_length;
		    current_length = (gulong)stat_buf.st_size;
		    delta_length = (current_length > last_length) ?
			(current_length - last_length) : 0l;
		    remaining_length = total_length - current_length;

		    cur_ms = DownloadCurrentMS();
		    if((cur_ms > last_millitime) &&
		       (last_millitime > 0l)
		    )
			delta_ms = cur_ms - last_millitime;
		    else
			delta_ms = 0l;
		    last_millitime = cur_ms;

		    /* Calculate the time left in seconds, if the result
		     * is 0 then it means the transfer has stalled
		     */
		    if((total_length > 0l) && (total_length != (gulong)-1) &&
		       (delta_length > 0l) && (remaining_length > 0l)
		    )
			time_remaining_sec = (gulong)(
			    (gfloat)delta_ms / (gfloat)delta_length *
			    (gfloat)remaining_length / 1000.0f
			);
		    else
			time_remaining_sec = 0l;

#if 0
/* The time left calculation is a bit "jumpy", this is most likely
 * due to the fact that this process is unable to determine precisely,
 * the moment, when additional bytes are downloaded to the target object
 * in order to accurately calculate the delta_ms that is
 * needed to predict how many bytes were downloaded during this
 * interval and ultimately the time remaining
 */
		    /* Append this time left value to the time left
		     * history buffer and then calculate the average
		     * time left
		     */
		    if(time_remaining_sec > 0l)
		    {
			const gint	m = MIN(
			    (time_left_sec_nitems + 1),
			    time_left_sec_max_items
			),
					im = m - 1;
			gint i;

			for(i = 0; i < im; i++)
			    time_left_sec_buf[i] = time_left_sec_buf[i + 1];
			time_left_sec_buf[im] = time_remaining_sec;
			time_left_sec_nitems = m;

			time_remaining_sec = DownloadGetAvgFromTimeBuffer(
			    time_left_sec_buf, time_left_sec_nitems
			);
		    }
#endif

		    /* Format time left string */
		    if(time_remaining_sec > 3600l)
			g_snprintf(
			    time_left_str, sizeof(time_left_str),
			    "%ld:%.2ld:%.2ld "
#if defined(PROG_LANGUAGE_SPANISH)
"quedándose"
#elif defined(PROG_LANGUAGE_FRENCH)
"restant"
#elif defined(PROG_LANGUAGE_GERMAN)
"bleiben"
#elif defined(PROG_LANGUAGE_ITALIAN)
"rimanere"
#elif defined(PROG_LANGUAGE_DUTCH)
"blijven"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"permanecer"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"forbliing"
#else
"left"
#endif
			    , (time_remaining_sec / 3600l),
			    (time_remaining_sec / 60l) % 60l,
			    (time_remaining_sec / 1l) % 60l
			);
		    else if(time_remaining_sec > 0l)
			g_snprintf(
			    time_left_str, sizeof(time_left_str),
			    "%ld:%.2ld "
#if defined(PROG_LANGUAGE_SPANISH)
"quedándose"
#elif defined(PROG_LANGUAGE_FRENCH)
"restant"
#elif defined(PROG_LANGUAGE_GERMAN)
"bleiben"
#elif defined(PROG_LANGUAGE_ITALIAN)
"rimanere"
#elif defined(PROG_LANGUAGE_DUTCH)
"blijven"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"permanecer"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"forbliing"
#else
"left"
#endif
			    , (time_remaining_sec / 60l),
			    (time_remaining_sec / 1l) % 60l
			);
		    else
			g_snprintf(
			    time_left_str, sizeof(time_left_str),
#if defined(PROG_LANGUAGE_SPANISH)
"atascado"
#elif defined(PROG_LANGUAGE_FRENCH)
"réalisé"
#elif defined(PROG_LANGUAGE_GERMAN)
"hingehalten"
#elif defined(PROG_LANGUAGE_ITALIAN)
"fermato"
#elif defined(PROG_LANGUAGE_DUTCH)
"geblokkeerde"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"imóvel"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"stoppet"
#else
"stalled"
#endif
			);

#if 0
g_print(
 "Time left %ld seconds (%ld left) %ld %ld\n",
 time_remaining_sec, remaining_length,
 current_length, total_length
);
#endif

		    /* Need to notify about the object being
		     * added?
		     *
		     * Note that since we stat() it we know it exists
		     */
		    if(!notified_object_added)
		    {
			EDVNotifyQueueObjectAdded(ctx, tar);
			EDVContextFlush(ctx);
			notified_object_added = TRUE;
		    }

		    /* Update the title string */
		    g_free(title);
		    if((total_length > 0l) && (total_length != (gulong)-1))
			title = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Descargar"
#elif defined(PROG_LANGUAGE_FRENCH)
"Télécharger"
#elif defined(PROG_LANGUAGE_GERMAN)
"Laden"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scaricare"
#elif defined(PROG_LANGUAGE_DUTCH)
"Downloaden"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Download"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Downloading"
#else
"Downloading"
#endif
			    " %s %.0f%%",
			    tar_name,
			    ((gfloat)current_length /
				(gfloat)total_length * 100.0f)
			);
		    else
			title = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Descargar"
#elif defined(PROG_LANGUAGE_FRENCH)
"Télécharger"
#elif defined(PROG_LANGUAGE_GERMAN)
"Laden"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scaricare"
#elif defined(PROG_LANGUAGE_DUTCH)
"Downloaden"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Download"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Downloading"
#else
"Downloading"
#endif
			     " %s", tar_name
			);

		    /* Update the message string */
		    g_free(message);
		    if((total_length > 0l) && (total_length != (gulong)-1))
		    {
			gchar	*total_size_str = STRDUP(EDVSizeStrDelim(total_length)),
				*cur_size_str = STRDUP(EDVSizeStrDelim(current_length));

			message = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Descargar:\n\
\n\
    %s (%s bytes)\n\
\n\
A:\n\
\n\
    %s (%s bytes) %s\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Télécharger:\n\
\n\
    %s (%s bytes)\n\
\n\
A:\n\
\n\
    %s (%s bytes) %s\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Laden:\n\
\n\
    %s (%s bytes)\n\
\n\
Zu:\n\
\n\
    %s (%s bytes) %s\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scaricare:\n\
\n\
    %s (%s bytes)\n\
\n\
A:\n\
\n\
    %s (%s bytes) %s\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Downloaden:\n\
\n\
    %s (%s bytes)\n\
\n\
Te:\n\
\n\
    %s (%s bytes) %s\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Download:\n\
\n\
    %s (%s bytes)\n\
\n\
A:\n\
\n\
    %s (%s bytes) %s\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Downloading:\n\
\n\
    %s (%s bytes)\n\
\n\
Til:\n\
\n\
    %s (%s bytes) %s\n"
#else
"Downloading:\n\
\n\
    %s (%s bytes)\n\
\n\
To:\n\
\n\
    %s (%s bytes) %s\n"
#endif
			    , p1, total_size_str,
			    p2, cur_size_str, time_left_str
			);
			g_free(total_size_str);
			g_free(cur_size_str);
		    }
		    else
		    {
			gchar *cur_size_str = STRDUP(EDVSizeStrDelim(current_length));

			message = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Descargar:\n\
\n\
    %s (??? bytes)\n\
\n\
A:\n\
\n\
    %s (%s bytes)\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Télécharger:\n\
\n\
    %s (??? octets)\n\
\n\
A:\n\
\n\
    %s (%s octets)\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Laden:\n\
\n\
    %s (??? bytes)\n\
\n\
Zu:\n\
\n\
    %s (%s bytes)\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scaricare:\n\
\n\
    %s (??? bytes)\n\
\n\
A:\n\
\n\
    %s (%s bytes)\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Downloaden:\n\
\n\
    %s (??? bytes)\n\
\n\
Te:\n\
\n\
    %s (%s bytes)\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Download:\n\
\n\
    %s (??? bytes)\n\
\n\
A:\n\
\n\
    %s (%s bytes)\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Downloading:\n\
\n\
    %s (??? bytes)\n\
\n\
Til:\n\
\n\
    %s (%s bytes)\n"
#else
"Downloading:\n\
\n\
    %s (??? bytes)\n\
\n\
To:\n\
\n\
    %s (%s bytes)\n"
#endif
			    , p1, p2, cur_size_str
			);
			g_free(cur_size_str);
		    }
		}	/* If total length is known, then get current length */

		check_count = 0;	/* Reset timmer */
	    }
	    else
	    {
		/* Not time to check, so just increment check timmer */
		check_count++;
	    }

	    /* Time to do notifies (every 10 seconds or longer)? */
	    if(notify_count >= 500l)
	    {
		if(notified_object_added)
		{
		    /* Send object modified notify to Endeavour */
		    EDVNotifyQueueObjectModified(ctx, tar, NULL);
		    EDVContextFlush(ctx);
		}

		notify_count = 0;	/* Reset timmer */
	    }
	    else
	    {
		/* Not time to notify, so just increment notify timmer */
		notify_count++;
	    }


	    /* Manage GTK+ events */
	    if(gtk_events_pending() > 0)
		gtk_main_iteration();

	    /* Update progress and set message (if it is not NULL).
	     * If the total length is know then we use a known progress
	     * method, otherwise we use the unknown method.
	     */
	    if((total_length > 0) && (total_length != (gulong)-1))
		ProgressDialogUpdate(
		    title, message, NULL, NULL,
		    (gfloat)current_length / (gfloat)total_length,
		    EDV_DEF_PROGRESS_BAR_TICKS,
		    TRUE
		);
	    else
		ProgressDialogUpdateUnknown(
		    title, message, NULL, NULL,
		    TRUE
		);

	    /* Reset title and message strings */
	    if(title != NULL)
	    {
		g_free(title);
		title = NULL;
	    }
	    if(message != NULL)
	    {
		g_free(message);
		message = NULL;
	    }

	    usleep(20000l);
	}

	/* Need to unmap progress dialog just in case */
	ProgressDialogBreakQuery(TRUE);

	/* Close standard output file */
	FClose(fp);

	/* Delete progress message */
	g_free(title);
	g_free(message);
	g_free(p1);
	g_free(p2);
	g_free(tar_name);


	/* Check if the object was downloaded by checking if the
	 * target object exists.  Also make sure that the user did not
	 * abort.
	 */
	if(stat(tar, &stat_buf) && !user_abort)
	{
	    /* Unable to stat destination file, this suggests that the
	     * object does not exist on the remote server or that the
	     * remote server is not responding.
	     */
	    gchar *buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Incapaz de descargar:\n\
\n\
    %s\n\
\n\
El objeto no existe ni el camarero remoto no responde.\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Impossible de télécharger:\n\
\n\
    %s\n\
\n\
L'objet n'existe pas ou le serveur éloigné ne répond pas.\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Unfähig zu laden:\n\
\n\
    %s\n\
\n\
Das objekt existiert nicht oder der entfernte diener antwortet nicht.\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Incapace per scaricare:\n\
\n\
    %s\n\
\n\
L'oggetto non esiste o il server remoto non risponde.\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Onbekwaam te downloaden:\n\
\n\
    %s\n\
\n\
Het voorwerp bestaat niet of de vere kelner antwoordt niet.\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Incapaz de baixar:\n\
\n\
    %s\n\
\n\
O objeto não existe nem o servidor remoto não responde.\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Maktesløs til download:\n\
\n\
    %s\n\
\n\
Objektet finnes ikke eller den fjerne tjeneren responderer ikke.\n"
#else
"Unable to download:\n\
\n\
    %s\n\
\n\
The object does not exist or the remote server is not responding.\n"
#endif
		, src
	    );
	    CDialogSetTransientFor(NULL);
	    CDialogGetResponse(
#if defined(PROG_LANGUAGE_SPANISH)
"Cargue Fallado",
		buf,
"El objeto no puede existir en el camarero remoto ni el camarero\n\
remoto no responde. Verifique por favor que el URL ese reffers al\n\
objeto es correcto y que el objeto existe verdaderamente en el\n\
remoto camarero. Si el camarero remoto no responde entonces usted\n\
puede querer tratar otra vez luego.\n",
#elif defined(PROG_LANGUAGE_FRENCH)
"Charger A Echoué",
		buf,
"L'objet peut ne pas exister sur le serveur distant ou le serveur\n\
distant ne répond pas. S'il vous plaît vérifier que l'URL se\n\
référant à l'objet est exact et que l'objet existe en fait sur\n\
 le serveur distant. Si le serveur distant ne répond pas alors\n\
vous pouvez réessayer plus tard.\n",
#elif defined(PROG_LANGUAGE_GERMAN)
"Laden Sie Versagt",
		buf,
"Das Objekt kann auf dem entfernten Diener nicht existieren\n\
oder der entfernte Diener antwortet nicht. Beglaubigen sie bitte,\n\
daß die URL jener reffers zum objekt richtig ist, und, daß das\n\
objekt tatsächlich auf dem entfernten diener existiert. Wenn der\n\
entfernte diener dann sie nicht antwortet, wollen können, wieder\n\
später zu versuchen.\n",
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scaricare Fallito",
		buf,
"L'oggetto non può esistere sul server remoto o il server remoto\n\
non risponde. Per favore di verificare che l'URL quel reffers\n\
all'oggetto è corretto e che l'oggetto esiste effettivamente sul\n\
server remoto. Se il server remoto non risponde poi lei può volere\n\
tentare ancora dopo.\n",
#elif defined(PROG_LANGUAGE_DUTCH)
"Download Geverzuimenene",
		buf,
"Het voorwerp zou op de vere kelner niet kunnen bestaan of de vere\n\
kelner antwoordt niet. Bevestiig alstublieft dat de URL dat reffers\n\
aan het voorwerp correct is en dat het voorwerp eigenlijk op de vere\n\
kelner bestaat. Indien de vere kelner dan u niet antwoordt kunnen\n\
willen zou om opnieuw later te proberen.\n",
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Baixe Fracassado",
		buf,
"O objeto não pode existir no servidor remoto nem o servidor remoto\n\
não responde. Por favor verifique-se que o URL aquele reffers ao\n\
objeto é correto e que o objeto realmente existe no servidor remoto.\n\
Se o servidor remoto não responde então pode querer tentar novamente\n\
mais tarde.\n",
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Download Sviktet",
		buf,
"Objektet finnes ikke på den fjerne tjeneren eller den fjerne\n\
tjeneren responderer ikke. Vær så snill og bekreft at URL den\n\
reffers til objektet er riktig og at objektet faktisk finnes på\n\
den fjerne tjeneren. Om den fjerne tjeneren ikke responderer da de\n\
vil ha prøve igjen senere.\n",
#else
"Download Failed",
		buf,
"The object may not exist on the remote server or\n\
the remote server is not responding.  Please verify\n\
that the URL that reffers to the object is correct\n\
and that the object actually exists on the remote\n\
server.  If the remote server is not responding then\n\
you may want to try again later.",
#endif
		CDIALOG_ICON_WARNING,
		CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP,
		CDIALOG_BTNFLAG_OK
	    );
	    CDialogSetTransientFor(NULL);
	    g_free(buf);
	    return(-3);		/* Target object does not exist */
	}
	else
	{
	    current_length = stat_buf.st_size;

	    /* Target object exists, suggesting that we downloaded
	     * it successfully (but also that the user may have
	     * aborted). So note that the target object size might be
	     * smaller than the one reported in the header.
	     *
	     * Notify Endeavour one last time about object modified,
	     * but notify it as an object added since 
	     */
	    if(notified_object_added)
		EDVNotifyQueueObjectModified(ctx, tar, NULL);
	    else
		EDVNotifyQueueObjectAdded(ctx, tar);
	    EDVContextFlush(ctx);

	    /* Total length known and does not match the current
	     * length?
	     *
	     * Also make sure the user did not abort
	     */
	    if((total_length > 0) && (total_length != (gulong)-1) &&
	       (total_length != current_length) && !user_abort
	    )
	    {
		gchar	*cur_size_str = STRDUP(EDVSizeStrDelim(current_length)),
			*total_size_str = STRDUP(EDVSizeStrDelim(total_length));

		gchar *buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"El objeto cargado tiene un tamaño de byte de %s, pero el\n\
el tamaño esperado del objeto debe ser los byte de %s.\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"L'objet chargé a une taille de %s octets, mais \n\
la taille prévue de l'objet était de %s octets.\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Das geladene objekt hat eine Größe von %s bytes, aber die\b\
erwartete größe des objekts soll %s bytes sein.\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"L'oggetto scaricato ha una misura di byte di %s, ma la\n\
misura aspettata dell'oggetto dovrebbe essere i byte di %s.\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Het gedownload voorwerp heeft een maat van %s bytes, maar de\n\
verwachte maat van het voorwerp zou %s bytes moeten zijn.\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O objeto baixado tem um tamanho de bytes de %s, mas o tamanho\n\
esperado do objeto deve ser bytes de %s.\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Downloaded objekt har en størrelse av %s byter, men den\n\
ventede størrelsen av objektet er %s byter.\n"
#else
"The downloaded object has a size of %s bytes, but the\n\
expected size of the object should be %s bytes.\n"
#endif
		    , cur_size_str, total_size_str
		);
		g_free(cur_size_str);
		g_free(total_size_str);

		CDialogSetTransientFor(NULL);
		CDialogGetResponse(
#if defined(PROG_LANGUAGE_SPANISH)
"Descargado Se Opone El Tamaño Inconsistancy",
		    buf,
"La descarga puede haber terminado prematuramente, se recomienda\n\
que usted reasuma la descarga descargando el objeto otra vez.\n",
#elif defined(PROG_LANGUAGE_FRENCH)
"Inconsistance de la taille de l'objet téléchargé",
		    buf,
"Le chargement a pu terminer prématurément, il est recommandé\n\
que vous repreniez à nouveau le téléchargement de l'objet.\n",
#elif defined(PROG_LANGUAGE_GERMAN)
"Geladene Objekt Größe Inconsistancy",
		    buf,
"Das wird verfrüht, es empfohlen lädt kann beendet haben, daß\n\
sie das wiederaufnehmen, durch Laden des Objekts wieder zu laden.\n",
#elif defined(PROG_LANGUAGE_ITALIAN)
"Inconsistancy Di Misura Di Oggetto Scaricato",
		    buf,
"Lo scarica può avere finito il prematurly, è raccomandato che lei\n\
riprende lo scarica da scaricare l'oggetto ancora.\n",
#elif defined(PROG_LANGUAGE_DUTCH)
"Gedownloade Voorwerp Maat Inconsistancy",
		    buf,
"Het downloadt voortijdig, het door downloaden heeft misschien\n\
beëindigd wordt aangeraden dat u het hervat van het voorwerp\n\
downloadt opnieuw.\n",
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Inconsistancy Baixado De Tamanho De Objeto",
		    buf,
"O download pode ter acabado prematuramente, é recomendado que\n\
resume o download por baixar o objeto novamente.\n",
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Downloaded Objekt Størrelse Inconsistancy",
		    buf,
"Download sluttet forhastet, det anbefaler at De gjenopptar den\n\
download ved downloading objektet igjen.\n",
#else
"Downloaded Object Size Inconsistancy",
		    buf,
"The download may have ended prematurly, it is recommended\n\
that you resume the download by downloading the object again.",
#endif
		    CDIALOG_ICON_WARNING,
		    CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP,
		    CDIALOG_BTNFLAG_OK
		);
		CDialogSetTransientFor(NULL);
		g_free(buf);
		return(-2);	/* Target object smaller in size */
	    }

	    /* We know the object appears to have been downloaded,
	     * but we need to report if it was successful or the user
	     * aborted
	     */
	    return(user_abort ? -4 : 0);
	}
}

/*
 *	Returns:
 *
 *	0	Success
 *	1	General error (object probably not downloaded)
 *	2	Object not downloaded (object not exist, server problem, etc)
 *	3	Download program that will be used to download the
 *		object does not exist
 *	4	User abort
 */
int main(int argc, char *argv[])
{
	gboolean initialized_gtk = FALSE;
	gboolean	need_confirmation = FALSE,
			beep_when_complete = FALSE,
			open_object = FALSE,
			download_last_object = FALSE;
	gulong		check_interval_ms = 1000l;
	GdkGeometryFlags geometry_flags = 0;
	GdkRectangle *geometry = NULL;
	gint i, status = 0;
	const gchar *arg;
	gchar *prog = NULL;
	gchar *source_url = NULL;
	gchar *destination_path = NULL;
	gchar *destination_file = NULL;
	gchar *stdout_file = NULL;
	edv_context_struct *ctx = NULL;

#define DO_SHUTDOWN	{		\
 if(ctx != NULL) {			\
  EDVContextSync(ctx);			\
  EDVContextDelete(ctx);		\
  ctx = NULL;				\
 }					\
					\
 g_free(prog);				\
 prog = NULL;				\
 g_free(source_url);			\
 source_url = NULL;			\
 g_free(destination_path);		\
 destination_path = NULL;		\
 g_free(destination_file);		\
 destination_file = NULL;		\
					\
 if(stdout_file != NULL) {		\
  unlink(stdout_file);			\
  g_free(stdout_file);			\
  stdout_file = NULL;			\
 }					\
					\
 if(initialized_gtk) {			\
  /* Shutdown dialogs */		\
  CDialogShutdown();			\
  PDialogShutdown();			\
  FileBrowserShutdown();		\
  ProgressDialogShutdown();		\
					\
  /* Reset the DND Icon */		\
  GUIDNDSetDragIcon(NULL, NULL, 0, 0);	\
					\
  initialized_gtk = FALSE;		\
 }					\
					\
 g_free(geometry);			\
 geometry = NULL;			\
}

	/* Set up signal callbacks */
#ifdef SIGINT
	signal(SIGINT, DownloadSignalCB);
#endif
#ifdef SIGTERM
	signal(SIGTERM, DownloadSignalCB);
#endif
#ifdef SIGKILL
	signal(SIGKILL, DownloadSignalCB);
#endif
#ifdef SIGSEGV
	signal(SIGSEGV, DownloadSignalCB);
#endif
#ifdef SIGSTOP
	signal(SIGSTOP, DownloadSignalCB);
#endif
#ifdef SIGCONT
	signal(SIGCONT, DownloadSignalCB);
#endif
#ifdef SIGPIPE
	signal(SIGPIPE, DownloadSignalCB);
#endif


	/* Parse arguments */
	for(i = 1; i < argc; i++)
	{
	    arg = argv[i];
	    if(arg == NULL)
		continue;

	    /* Help */
	    if(!g_strcasecmp(arg, "--help") ||
	       !g_strcasecmp(arg, "-help") ||
	       !strcmp(arg, "--h") ||
	       !strcmp(arg, "-h") ||
	       !strcmp(arg, "-?")
	    )
	    {
		g_print("%s", PROG_HELP_MESG);
		status = 0;
		DO_SHUTDOWN
		return(status);
	    }
	    /* Version */
	    else if(!g_strcasecmp(arg, "--version") ||
		    !g_strcasecmp(arg, "-version")
	    )
	    {
		g_print("%s %s\n%s", PROG_NAME, PROG_VERSION, PROG_COPYRIGHT);
		status = 0;
		DO_SHUTDOWN
		return(status);
	    }
	    /* Beep when the download has been complete? */
	    else if(!g_strcasecmp(arg, "--beep") ||
		    !g_strcasecmp(arg, "-beep") ||
		    !strcmp(arg, "--b") ||
		    !strcmp(arg, "-b")
	    )
	    {
		beep_when_complete = TRUE;
	    }
	    /* Query the user for confirmation before downloading? */
	    else if(!g_strcasecmp(arg, "--confirm") ||
		    !g_strcasecmp(arg, "-confirm") ||
		    !strcmp(arg, "--c") ||
		    !strcmp(arg, "-c")
	    )
	    {
		need_confirmation = TRUE;
	    }
	    /* Open the object afterwards (only if the download was
	     * successful and complete)?
	     */
	    else if(!g_strcasecmp(arg, "--open") ||
		    !g_strcasecmp(arg, "-open") ||
		    !strcmp(arg, "--o") ||
		    !strcmp(arg, "-o")
	    )
	    {
		open_object = TRUE;
	    }
	    /* (Re)download the last object? */
	    else if(!g_strcasecmp(arg, "--last") ||
		    !g_strcasecmp(arg, "-last") ||
		    !strcmp(arg, "--l") ||
		    !strcmp(arg, "-l")
	    )
	    {
		download_last_object = TRUE;
	    }
	    /* Check download progress and update messages interval
	     * in milliseconds (default is 1000)?
	     */
	    else if(!g_strcasecmp(arg, "--interval") ||
		    !g_strcasecmp(arg, "-interval") ||
		    !g_strcasecmp(arg, "--int") ||
		    !g_strcasecmp(arg, "-int") ||
		    !g_strcasecmp(arg, "--i") ||
		    !g_strcasecmp(arg, "-i")
	    )
	    {
		i++;
		if(i < argc)
		{
		    check_interval_ms = MAX(ATOL(argv[i]), 1l);
		}
		else
		{
		    g_printerr(
"%s: Requires argument.\n",
			arg
		    );
		    status = 2;
		    DO_SHUTDOWN
		    return(status);
		}
	    }
	    /* Geometry */
	    else if(!g_strcasecmp(arg, "--geometry") ||
		    !g_strcasecmp(arg, "-geometry")
	    )
	    {
		i++;
		arg = (i < argc) ? argv[i] : NULL;
		if(arg != NULL)
		{
		    if(geometry == NULL)
		    {
			gint x, y, width, height;

			geometry = (GdkRectangle *)g_malloc0(
			    sizeof(GdkRectangle)
			);
			geometry_flags = GUIParseGeometry(
			    arg, &x, &y, &width, &height
			);
			geometry->x = x;
			geometry->y = y;
			geometry->width = width;
			geometry->height = height;
		    }
		}
		else 
		{
		    g_printerr(
			"%s: Requires argument\n",
			argv[i - 1]
		    );
		    status = 2;
		    DO_SHUTDOWN
		    return(status);
		}
	    }
	    /* Single character argument? */
	    else if((*arg == '-') ? (arg[1] != '-') : FALSE)
	    {
		const gchar *v = arg + 1;
		gchar c;

		while(*v != '\0')
		{
		    c = *v;
		    if(c == 'b')
		    {
			beep_when_complete = TRUE;
		    }
		    else if(c == 'c')
		    {
			 need_confirmation = TRUE;
		    }
		    else if(c == 'o')
		    {
			 open_object = TRUE;
		    }
		    else if(c == 'l')
		    {
			 download_last_object = TRUE;
		    }
		    else
		    {
			g_printerr(
"-%c: Unsupported argument.\n",
			    c
			);
			status = 2;
			DO_SHUTDOWN
			return(status);
		    }
		    v++;
		}
	    }
	    /* Non-option argument? */
	    else if((*arg != '-') && (*arg != '+'))
	    {
		/* All else assume source url or destination path */
		if(source_url == NULL)
		    source_url = STRDUP(arg);
		else if(destination_path == NULL)
		    destination_path = STRDUP(arg);
	    }
	    else
	    {
		g_printerr(
"%s: Unsupported argument.\n",
		    arg
		);
		status = 2;
		DO_SHUTDOWN
		return(status);
	    }
	}

	/* Set GTK+ locale */
	gtk_set_locale();

	/* Initialize GTK+ as needed */
	if(!initialized_gtk)
	{
	    if(!gtk_init_check(&argc, &argv))
	    {
		g_printerr("Unable to initialize GTK.\n");
		status = 1;
		DO_SHUTDOWN
		return(status);
	    }
	    initialized_gtk = TRUE;
	}

	/* Initialize GDK RGB buffers system */
	gdk_rgb_init();

	/* Initialize dialogs */
	CDialogInit();
	PDialogInit();
	FileBrowserInit();
	ProgressDialogInit();

	/* Initialize Endeavour context */
	ctx = EDVContextNew();
	EDVContextLoadConfigurationFile(ctx, NULL);


	/* (Re)download last object? */
	if(download_last_object)
	{
	    /* Read last download configuration file and see if there
	     * was an object recorded, make sure that we at least have
	     * the source URL
	     */
	    gint download_status = 0;
	    DownloadCFGGetLast(
		ctx,
		&source_url,
		&destination_path,
		&download_status
	    );
	    if(source_url == NULL)
	    {
		CDialogSetTransientFor(NULL);
		CDialogGetResponse(
#if defined(PROG_LANGUAGE_SPANISH)
"Ningún Objeto Para Descargar",
"No hay el registro de un previamente descargado se opone\n\
para descargar.",
#elif defined(PROG_LANGUAGE_FRENCH)
"Aucun Objet à Télécharger",
"Il n'y a pas de trace d'un objet précédemment\n\
téléchargé à télécharger de nouveau.",
#elif defined(PROG_LANGUAGE_GERMAN)
"Kein Objekt Zu Laden",
"Es gibt keine aufzeichnung von einem vorher geladenen objekt\n\
zu laden.",
#elif defined(PROG_LANGUAGE_ITALIAN)
"Nessuno Oggetto Di Scaricar",
"Non ci è disco di un oggetto precedentemente scaricato di\n\
scaricare.",
#elif defined(PROG_LANGUAGE_DUTCH)
"Geen Voorwerp Te Downloaden",
"Er is geen verslag van een vroeger gedownload voorwerp te\n\
downloaden.",
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Nenhum Objeto Baixar",
"Não há nenhum registro de um objeto previamente baixado\n\
baixar.",
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Ingen Objekt Til Download",
"Der er ikke noen protokoll av et tidligere downloaded objekt\n\
til download.",
#else
"No Object To Download",
"There is no record of a previously downloaded object\n\
to (re)download.",
#endif
		    NULL,
		    CDIALOG_ICON_INFO,
		    CDIALOG_BTNFLAG_OK,
		    CDIALOG_BTNFLAG_OK
		);
		CDialogSetTransientFor(NULL);

		status = 2;
		DO_SHUTDOWN
		return(status);
	    }
	}

	/* Use current working directory as destination path if the
	 * destination path is not obtained from the command line.
	 */
	if(STRISEMPTY(destination_path))
	{
	    g_free(destination_path);
	    destination_path = STRDUP(g_get_current_dir());
	}


	/* No source url given? then query user for url */
	if((source_url != NULL) ? (*source_url == '\0') : TRUE)
	{
	    gchar **strv;
	    gint strc;

	    PDialogDeleteAllPrompts();
	    PDialogAddPrompt(
		NULL, "URL:", NULL
	    );
	    PDialogSetPromptTip(
		-1,
#if defined(PROG_LANGUAGE_SPANISH)
"Entre el URL (comenzar con http:// o el ftp://) del objeto eso\
 usted quiere cargar"
#elif defined(PROG_LANGUAGE_FRENCH)
"Entrer l'URL (en commencant par http:// ou ftp://) de l'objet\
 que vous voulez télécharger"
#elif defined(PROG_LANGUAGE_GERMAN)
"Tragen sie die URL (der mit http:// oder ftp:// anfängt) vom objekt,\
 das sie laden wollen ein"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Entrare l'URL (cominciando con http:// o con ftp://) dell'oggetto che\
 lei vuole scaricare"
#elif defined(PROG_LANGUAGE_DUTCH)
"Ga de (, die met http:// of ftp:// begint) URL van het voorwerp binnen\
 dat u downloaden wil"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Entre o URL (começando com http:// ou ftp://) do objeto que você quer\
 baixar"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Gå inn i URL (start med http:// eller ftp://) av objektet som De vil\
 ha download"
#else
"Enter the URL (starting with http:// or ftp://) of the\
 object that you want to download"
#endif
	    );
	    PDialogAddPromptWithBrowse(
		NULL,
#if defined(PROG_LANGUAGE_SPANISH)
"A"
#elif defined(PROG_LANGUAGE_FRENCH)
"A"
#elif defined(PROG_LANGUAGE_GERMAN)
"Zu"
#elif defined(PROG_LANGUAGE_ITALIAN)
"A"
#elif defined(PROG_LANGUAGE_DUTCH)
"Te"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"A"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Til"
#else
"To"
#endif
		":", destination_path,
		NULL, DownloadBrowseTargetPathCB
	    );
	    PDialogSetPromptCompletePath(-1);
	    PDialogSetPromptTip(
		-1,
#if defined(PROG_LANGUAGE_SPANISH)
"Entre el sendero repleto de la guía que usted quiere para\
 descargar el objeto a o le sale blanco para descargar a la\
 guía actual"
#elif defined(PROG_LANGUAGE_FRENCH)
"Entrer le nom complet du répertoire où vous voulez\
 télécharger l'objet ou ne rien indiquer pour télécharger dans\
 le répertoire actuel"
#elif defined(PROG_LANGUAGE_GERMAN)
"Tragen sie den vollen pfad des verzeichnisses, das sie das\
 objekt zu oder laden wollen, verlassen es leerstelle ein, zum\
 jetzigen verzeichnis zu laden"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Entrare il sentiero pieno dell'elenco che lei vuole scaricare\
 l'oggetto a o lasciare lo spazio vuoto di esso per scaricare\
 all'elenco attuale"
#elif defined(PROG_LANGUAGE_DUTCH)
"Ga het vol pad van de gids dat u het voorwerp te downloaden wil\
 binnen of verlaat het leegte om te de huidig gids te downloaden"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Entre o pleno caminho do guia que você quer baixar o objeto a\
 ou sai de ele lacuna baixar ao guia atual"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Gå inn i den fulle stien av katalogen som De vil ha download\
 objektet til eller forlate det tomrom til download til den\
 nåværendee katalogen"
#else
"Enter the full path of the directory that you want to download the\
 object to or leave it blank to download to the current directory"
#endif
	    );
	    if(geometry != NULL)
	    {
		GtkWidget *w = PDialogGetToplevel();
		if(w != NULL)
		{
		    gtk_widget_set_uposition(
			w,
			(geometry_flags & GDK_GEOMETRY_X) ?
			    geometry->x : 0,
			(geometry_flags & GDK_GEOMETRY_Y) ?
			    geometry->y : 0
		    );
		}
	    }
	    PDialogSetSize(450, -1);
	    strv = PDialogGetResponseIconData(
		PROG_NAME,
#if defined(PROG_LANGUAGE_SPANISH)
"Entre el URL (empezando con http:// o ftp://) del objeto que usted\n\
quiere descargar. Si usted sale el blanco de campo de A: entonces\n\
el objeto será descargado a la guía actual."
#elif defined(PROG_LANGUAGE_FRENCH)
"Entrer l'URL (en commençant par http:// ou ftp://) de l'objet que\n\
vous voulez télécharger. Si vous laissez le champ du destinataire vide A: alors\n\
l'objet sera téléchargé dans le répertoire actuel."
#elif defined(PROG_LANGUAGE_GERMAN)
"Tragen sie die URL (der mit http:// oder ftp:// anfängt) vom objekt,\n\
das sie laden wollen ein. Wenn sie die Zu: feld leerstelle dann das\n\
objekt verlassen, zum jetzigen verzeichnis wird geladen werden."
#elif defined(PROG_LANGUAGE_ITALIAN)
"Entrare l'URL (cominciando con http:// o con ftp://) dell'oggetto\n\
che lei vuole scaricare. Se lei lascia lo spazio vuoto di campo di\n\
A: di il poi l'oggetto sarà scaricato all'elenco attuale."
#elif defined(PROG_LANGUAGE_DUTCH)
"Ga de (, die met http:// of ftp:// begint) URL van het voorwerp\n\
binnen dat u downloaden wil. Indien u de Te: veld leegte dan het\n\
voorwerp verlaat te de huidig gids zal gedownload worden."
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Entre o URL (começando com http:// ou ftp://) do objeto que você\n\
quer baixar. Se sai da lacuna de campo de A: então o objeto será\n\
baixado ao guia atual."
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Gå inn i URL (start med http:// eller ftp://) av objektet som\n\
de vil ha download. Om De forlater Til: felttomrom da objektet\n\
er downloaded til den nåværendee katalogen."
#else
"Enter the URL (starting with http:// or ftp://) of the object that\n\
you want to download. If you leave the To: field blank then the\n\
object will be downloaded to the current directory."
#endif
		, NULL,
		(guint8 **)icon_download_file_32x32_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Descarga",
"Cancele",
#elif defined(PROG_LANGUAGE_FRENCH)
"Chargement",
"Annuler",
#elif defined(PROG_LANGUAGE_GERMAN)
"Laden",
"Heben",
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scaricare",
"Annullare",
#elif defined(PROG_LANGUAGE_DUTCH)
"Download",
"Annuleer",
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Download",
"Cancelamento",
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Download",
"Kanseller",
#else
"Download",
"Cancel",
#endif
		PDIALOG_BTNFLAG_SUBMIT | PDIALOG_BTNFLAG_CANCEL,
		PDIALOG_BTNFLAG_SUBMIT,
		&strc
	    );
	    if((strv != NULL) && (strc > 0))
	    {
		/* Get source URL from first string */
		const gchar *s = strv[0];
		if(!STRISEMPTY(s))
		{
		    g_free(source_url);
		    source_url = STRDUP(s);
		}

		/* Get destination path from second string (if any) */
		if(strc > 1)
		{
		    s = strv[1];
		    if(!STRISEMPTY(s))
		    {
			g_free(destination_path);
			destination_path = STRDUP(s);
		    }
		}
	    }

	    /* If no source url was obtained than that implies the user
	     * has canceled
	     */
	    if(STRISEMPTY(source_url))
	    {
		status = 4;
		DO_SHUTDOWN
		return(status);
	    }
	}


	/* Use current working directory as destination path if the
	 * destination path is not given
	 *
	 * Note that we have to do this again since the user may have
	 * been queried above and no destination path was given
	 */
	if(STRISEMPTY(destination_path))
	{
	    g_free(destination_path);
	    destination_path = STRDUP(g_get_current_dir());
	}


	/* Change working directory to the destination path only if the
	 * destination path is given, otherwise use current directory
	 */
	if(ISPATHDIR(destination_path))
	{
	    const gchar *s = strrchr(source_url, '/');
	    if(s != NULL)
		destination_file = g_strdup_printf(
		    "%s/%s", destination_path, s + 1
		);
	    else
		destination_file = STRDUP(destination_path);

	    EDVSetCWD(destination_path);
	}
	else if(destination_path != NULL)
	{
	    /* Destination path is given, but it does not appear to be
	     * a directory, so instead get its parent path and change
	     * to its directory
	     */
	    const gchar	*s = strrchr(source_url, '/'),
			*parent = GetParentDir(destination_path);
	    EDVSetCWD(parent);

	    if(s != NULL)
		destination_file = g_strdup_printf(
		    "%s/%s", parent, s + 1
		);
	    else
		destination_file = STRDUP(destination_path);
	}
	else
	{
	    g_free(destination_path);
	    destination_path = STRDUP(g_get_current_dir());
	}


	/* Need to make initial confirmation? */
	if(need_confirmation)
	{
	    gint response;
	    gchar *buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Descarga:\n\
\n\
    %s\n\
A:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Chargement:\n\
\n\
    %s\n\
A:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Laden:\n\
\n\
    %s\n\
Zu:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scaricare:\n\
\n\
    %s\n\
A:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Download:\n\
\n\
    %s\n\
Te:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Download:\n\
\n\
    %s\n\
A:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Download:\n\
\n\
    %s\n\
Til:\n\
\n\
    %s\n"
#else
"Download:\n\
\n\
    %s\n\
\n\
To:\n\
\n\
    %s\n"
#endif
		, source_url, destination_file
	    );
	    CDialogSetTransientFor(NULL);
	    response = CDialogGetResponseIconData(
#if defined(PROG_LANGUAGE_SPANISH)
"Confirme La Descarga"
#elif defined(PROG_LANGUAGE_FRENCH)
"Confirme le chargement"
#elif defined(PROG_LANGUAGE_GERMAN)
"Bestätigen Sie Lädt"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Confermare Scaricare"
#elif defined(PROG_LANGUAGE_DUTCH)
"Bevestiig Downloadt"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Confirme Download"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Bekreft Download"
#else
"Confirm Download"
#endif
		, buf, NULL,
		(guint8 **)icon_download_file_32x32_xpm,
		CDIALOG_BTNFLAG_YES | CDIALOG_BTNFLAG_NO,
		CDIALOG_BTNFLAG_YES
	    );
	    CDialogSetTransientFor(NULL);
	    g_free(buf);

	    switch(response)
	    {
	      case CDIALOG_RESPONSE_NO:
	      case CDIALOG_RESPONSE_NOT_AVAILABLE:
		status = 4;
		DO_SHUTDOWN
		return(status);
		break;
	    }
	}

	/* Destination file already exists? */
	if(!access(destination_file, F_OK))
	{
	    gint response;
	    gchar *buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Reasuma cargue de existente se opone:\n\
\n\
    %s\n\
\n\
El chasquido en el \"Si\" de para reasumir carga.\n\
El chasquido en el \"No\" de para escribir para reemplazar objeto\n\
local con objeto remoto.\n\
El chasquido en el \"Cancela\" de para cancelar el carga.\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Reprendre le chargement d'objet existant:\n\
\n\
    %s\n\
\n\
Clicquer sur \"Oui\" reprendre le chargement.\n\
Clicquer sur \"Non\" remplace l'objet local par l'objet distant.\n\
Clicquer sur \"Annule\" pour annuler le chargement.\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Lebenslauf lädt von existieren objekt:\n\
\n\
    %s\n\
\n\
Klicken auf \"Ja\" wiederaufzunehmen zu laden.\n\
Klicken auf \"Nein\", örtliches objekt mit entferntem objekt zu\n\
überschreiben.\n\
Klicken auf "Hebt", das aufzuheben, lädt.\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Riprendere scaricare di oggetto esistente:\n\
\n\
    %s\n\
\n\
Scattare su \"Sì\" di riprendere scaricare.\n\
Scattare su \"No\" di sovrascrivere l'oggetto locale con\n\
l'oggetto remoto.\n\
Lo scatto su \"Annulla\" per annullare lo scarica.\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Cv download van bestaan voorwerp:\n\
\n\
    %s\n\
\n\
Klik op \"Ja\" te hervatten downloadt.\n\
Klik op \"Geen\" plaatselijk voorwerp met ver voorwerp te\n\
beschrijven.\n\
Klik \"Annuleert\" op om het te annuleren downloadt.\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Resuma download de objeto existente:\n\
\n\
    %s\n\
\n\
Clique em \"Sim\" resumir download.\n\
Clique em \"Não\" a overwrite objeto local com objeto remoto.\n\
Clique em \"Cancelamento\" cancelar o download.\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Gjenoppta download av å finnes objekt:\n\
\n\
    %s\n\
\n\
Klikk på \"Ja\" gjenoppta download.\n\
Klikk på \"Ingen\" overskrive lokalt objekt med fjernt objekt.\n\
Klikk på \"Kansellerer\" kansellere download.\n"
#else
"Resume download of existing object:\n\
\n\
    %s\n\
\n\
Click on \"Yes\" to resume download.\n\
Click on \"No\" to overwrite local object with remote object.\n\
Click on \"Cancel\" to cancel the download.\n"
#endif
		, destination_file
	    );
	    CDialogSetTransientFor(NULL);
	    response = CDialogGetResponseIconData(
#if defined(PROG_LANGUAGE_SPANISH)
"Confirme Reasuma",
		buf,
"El objeto que usted tratan de cargar aparece a\n\
existe ya localmente. Si el objeto local existente\n\
era sólo parcialmente cargado (e.g. debido a un interrumpido\n\
la transferencia) usted debe chasquear en \"Sí\" reasumir\n\
cargarlo. Si usted desea escribir para  reemplazar el\n\
existente objeto local con el objeto que usted cargan\n\
entonces el chasquido en \"No\". Si usted está no seguro lo\n\
que hacer ni usted quiere no cargar el objeto entonces\n\
chasquido en \"Cancela\".\n",
#elif defined(PROG_LANGUAGE_FRENCH)
"Confirmer Reprendre",
		buf,
"L'objet que vous essayez de charger existe déjà localement.\n\
 Si l'objet local existe seulement en raison d'un téléchargement précédent\n\
(e.g. grâce à un transfert interrompu) vous devez cliquer\n\
sur \"Oui\" pour reprendre le chargement. Si vous souhaitez\n\
superposer l'objet local existant avec l'objet que vous\n\
téléchargez alors clicquer sur \"Non\". Si vous n'êtes pas sûr de\n\
 ce que vous devez faire, alors clicquer sur \"Annule\".\n",

#elif defined(PROG_LANGUAGE_GERMAN)
"Bestätigen Sie Lebenslauf",
		buf,
"Das objekt, das sie versuchen, zu laden, erscheint schon,\n\
örtlich zu existieren. Wenn das existierende örtliche objekt nur\n\
teilweise (e.g. aufgrund einer unterbrochenen Übertragung) sie\n\
geladen wurde, auf sollen \"Ja\" klicken, wieder anzufangen, es zu\n\
laden. Wenn sie wünschen, das existierende örtliche objekt mit dem\n\
objekt sie zu überschreiben, dann laden klicken auf \"Nein\".\n\
Wenn sie nicht sicher sind was, zu machen oder sie \"Aufhebt\" das\n\
objekt dann klicken auf nicht wollen laden.\n",
#elif defined(PROG_LANGUAGE_ITALIAN)
"Confermare Riprendere",
		buf,
"L'oggetto che lei tentano scaricare appare già esistere localmente.\n\
Se l'esistere l'oggetto locale parzialmente è stato soltanto\n\
scaricato (e.g. dovuto a un trasferimento interrotto) lei dovrebbe\n\
scattare su \"Sì\" di riprendere per scaricare esso. Se lei desidera\n\
sovrascrivere l'esistere l'oggetto locale con l'oggetto che lei\n\
scaricano poi lo scatto su \"No\". Se lei non sono sicuro ciò che di\n\
fare o lei non vuole scaricare l'oggetto il poi scatto su \"Annulla\".\n",
#elif defined(PROG_LANGUAGE_DUTCH)
"Bevestiig Cv",
		buf,
"Het voorwerp dat u probeert te downloaden verschijnt reeds om\n\
plaatselijk te bestaan. Indien het bestaand plaatselijk voorwerp\n\
enige gedeeltelijk werd gedownload (e.g. tengevolge van een\n\
onderbrekenene overdracht) u op \"Ja\" zou moeten klikken downloaden\n\
het te hervatten. Indien u wenst het bestaand plaatselijk voorwerp\n\
met het voorwerp u te beschrijven dan downloadt klik op \"Geen\".\n\
Indien u niet zeker bent wat te doen of u \"Annuleert\" het voorwerp\n\
dan klik op niet wil downloaden.\n",
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Confirme Resume",
		buf,
"O objeto que você tentam baixar aparece já existir localmente.\n\
Se o existir objeto local só parcialmente foi baixado (e.g. devido\n\
a uma transferência interrompida) deve clicar em \"Sim\" resumir\n\
download ele. Se deseja a overwrite o existir objeto local com o\n\
objeto que você baixam então estalido em \"Não\". Se você não estão\n\
seguro o que fazer nem você não quer baixar o objeto então estalido\n\
em \"Cancelamento\".\n",
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Bekreft Fortsetter",
		buf,
"Objektet som De prøver til download kommer fram allerede finnes\n\
lokalt. Om finnesingen av lokalt objekt var bare delvis downloaded\n\
(e.g. på grunn av en avbrytet overføring) De klikker på \"Ja\"\n\
gjenoppta downloading det. Om De ønsker overskrive finnesingen av\n\
lokalt objekt med objektet De er downloading da klikk på \"Ingen\".\n\
Om De er ikke sikker hva gjøre eller De gjør ikke vil ha download\n\
objektet da klikk på \"Kansellerer\".\n",
#else
"Confirm Resume",
		buf,
"The object that you are trying to download appears to\n\
already exist locally.  If the existing local object\n\
was only partially downloaded (e.g. due to an interrupted\n\
transfer) you should click on \"Yes\" to resume\n\
downloading it.  If you wish to overwrite the existing\n\
local object with the object you are downloading then\n\
click on \"No\".  If you are not sure what to do or you\n\
do not want to download the object then click on \"Cancel\".",
#endif
		(guint8 **)icon_download_file_32x32_xpm,
		CDIALOG_BTNFLAG_YES | CDIALOG_BTNFLAG_NO |
		CDIALOG_BTNFLAG_CANCEL | CDIALOG_BTNFLAG_HELP,
		CDIALOG_BTNFLAG_YES
	    );
	    CDialogSetTransientFor(NULL);
	    g_free(buf);

	    switch(response)
	    {
	      case CDIALOG_RESPONSE_CANCEL:
	      case CDIALOG_RESPONSE_NOT_AVAILABLE:
		status = 4;
		DO_SHUTDOWN
		return(status);
		break;

	      case CDIALOG_RESPONSE_NO:
		/* Overwrite, so remove the destination file */
		unlink(destination_file);
		/* Do not notify Endeavour about the removed file */
		break;
	    }
	}

	/* Get the GNU WGet program */
	prog = EDVWhich(WGET_PROG);
	if(prog == NULL)
	{
	    gchar *buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Incapaz de encontrar el programa de la descarga:\n\
\n\
    %s\n\
\n\
Verifique por favor que el programa es instalado en una\n\
ubicacion especificada por el ambiente de %s y que\n\
es ejecutable por este programa.",
#elif defined(PROG_LANGUAGE_FRENCH)
"Impossible de trouver le programme de téléchargement:\n\
\n\
    %s\n\
\n\
S'il vous plait verifier que le programme soit installe\n\
a l'emplacement spécifié par l'environnement de\n\
%s et que c'est éxécutable par ce programme.",
#elif defined(PROG_LANGUAGE_GERMAN)
"Unfahig, das downloadprogramm zu finden:\n\
\n\
    %s\n\
\n\
Bitte beglaubigt, dass das programm von der %s umwelt\n\
an einem ort installiert wird, der und angegeben wird,\n\
dass es ausfuhrbar durch dieses programm ist.",
#elif defined(PROG_LANGUAGE_ITALIAN)
"Incapace per trovare lo scarica il programma:\n\
\n\
    %s\n\
\n\
Per favore di verificare che il programma e installato a\n\
una posizione specificata dall'ambiente di %s e che\n\
e eseguibile da questo programma.",
#elif defined(PROG_LANGUAGE_DUTCH)
"Onbekwaam om het te vinden downloadt programma:\n\
\n\
    %s\n\
\n\
Bevestigt u alstublieft dat het programma door de %s\n\
omgeving aan een locatie wordt geinstalleerd die door dit\n\
programma gespecificeerd wordt en dat het uitvoerbaar is.",
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Incapaz de achar o programa de download:\n\
\n\
    %s\n\
\n\
Por favor verifique-se que o programa e instalado numa\n\
situacao especificado pelo ambiente de %s e que e\n\
executable por este programa.",
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Maktesl?s finne download program:\n\
\n\
    %s\n\
\n\
Ver sa snill og bekreft at programet installerer pa en\n\
plassering spesifisert ved %s miljo og at det er\n\
gjennomforbar ved dette programet.",
#else
"Unable to find the download program:\n\
\n\
    %s\n\
\n\
Please verify that the program is installed at a location\n\
specified by the %s environment and that it is\n\
executable by this program.",
#endif
		WGET_PROG, ENV_VAR_NAME_PATH
	    );
	    CDialogSetTransientFor(NULL);
	    CDialogGetResponse(
#if defined(PROG_LANGUAGE_SPANISH)
"El Programa De La Descarga No Encontró",
		buf,
"El programa de la descarga se utiliza para realizar la descarga\n\
verdadera, se debe instalar en su sistema en la ubicación\n\
especificada encima de para permite este programa es capaz de\n\
descargar objetos.\n",
#elif defined(PROG_LANGUAGE_FRENCH)
"Le Programme de chargement n'a pas trouvé",
		buf,
"Le programme de chargement est utilisé pour exécuter le\n\
chargement véritable, il doit être installé sur votre système\n\
à l'emplacement spécifié afin de rendre capable au-dessus ce\n\
programme peut télécharger des objets.\n",
#elif defined(PROG_LANGUAGE_GERMAN)
"Laden Sie Programm, Das Gefunden Wird Nicht",
		buf,
"Das ist programm benutzt lädt, das eigentliche durchzuführen,\n\
es auf ihrem system am ort lädt oben muß installiert werden hat\n\
angegeben, um zu ermöglichen, dieses programm kann objekte\n\
laden.\n",
#elif defined(PROG_LANGUAGE_ITALIAN)
"Non scaricare il Programma Trovato",
		buf,
"Lo scarica il programma è usato per eseguire il reale scarica,\n\
deve essere installato sul suo sistema alla posizione\n\
specificata sopra per permettere questo programma è in grado di\n\
scaricare gli oggetti.\n",
#elif defined(PROG_LANGUAGE_DUTCH)
"Download Niet Programma Vond",
		buf,
"Het is programma gebruikt downloadt om het eigenlijk te\n\
verrichten, downloadt het op je systeem aan de plaats, die\n\
boven om gespecificeerd is om aan de gelegenheid deze programma\n\
te geven voorwerpen moet geïnstalleerd worden kan downloaden.\n",
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Programa De Download Não Achou",
		buf,
"O programa de download é usado para executar o download real,\n\
deve ser instalado em seu sistema na localidade especificado\n\
acima para capacitar este programa é capaz de baixar objetos.\n",
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Download Program Funnet Ikke",
		buf,
"Download program bruker gjennomføre den aktuelle download,\n\
installert det på Deres system på plasseringen som spesifisert\n\
over muliggjøre dette programet er kyndig til download objekt.\n",
#else
"Download Program Not Found",
		buf,
"The download program is used to perform the actual download,\n\
it must be installed on your system at the location specified\n\
above in order to enable this program is able to download\n\
objects.\n",
#endif
		CDIALOG_ICON_ERROR,
		CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP,
		CDIALOG_BTNFLAG_OK
	    );
	    CDialogSetTransientFor(NULL);
	    g_free(buf);

	    status = 3;
	    DO_SHUTDOWN
	    return(status);
	}

	/* Generate tempory stdout file */
	stdout_file = EDVTmpName(NULL);


	/* Execute the download program and monitor the download */
	if(destination_file != NULL)
	{
	    const gulong start_time = (gulong)time(NULL);
	    gchar *cmd = g_strdup_printf(
		"\"%s\" \"%s\" --tries=1 --progress=dot -c",
		prog, source_url
	    );
	    /* Execute the download command
	     *
	     * Note that wget writes stdout output to stderr
	     */
	    const gint p = ExecOE(cmd, NULL, stdout_file);
	    if(p <= 0)
	    {
		/* An error occured while executing the download command */
		gchar *s = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Incapaz de ejecutar la orden de la descarga:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Impossible d'exécuter l'ordre de chargement:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Unfähig, durchzuführen, befehl lädt:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Incapace per eseguire scarica il comando:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Onbekwaam uit te voeren bevel downloadt:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Incapaz de executar comando de download:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Maktesløs utføre download kommando:\n\
\n\
    %s\n"
#else
"An error occured while executing the download command:\n\
\n\
    %s\n"
#endif
		    , cmd
		);
		CDialogSetTransientFor(NULL);
		CDialogGetResponse(
#if defined(PROG_LANGUAGE_SPANISH)
"Descargue Fallado",
		    s,
"La orden utilizó para descargar el objeto no se podría\n\
ejecutar, verifica por favor que el programa de la descarga\n\
existe en la ubicación especificada encima de y es ejecutable.\n",
#elif defined(PROG_LANGUAGE_FRENCH)
"ECHEC de téléchargement",
		    s,
"La commande utiliséé pour télécharger l'objet ne pourrait pas\n\
être exécuté, s'il vous plaît vérifier que le programme de\n\
chargement existe à l'emplacement spécifié au-dessus  et est\n\
éxécutable.\n",
#elif defined(PROG_LANGUAGE_GERMAN)
"Laden Sie Versagt",
		    s,
"Der befehl könnte das objekt nicht durchgeführt werden hatte\n\
geladen, beglaubigt bitte, daß das programm lädt, am Ort ober\n\
existiert hat angegeben und ist ausführbar.\n",
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scaricare Fallito",
		    s,
"Il comando ha usato per scaricare l'oggetto non potrebbe\n\
essere eseguito, verifica per favore che lo scarica il programma\n\
esiste alla posizione specificata e è sopra eseguibile.\n",
#elif defined(PROG_LANGUAGE_DUTCH)
"Download Geverzuimenene",
		    s,
"Het bevel zou het voorwerp niet kunnen uitgevoerd worden heeft\n\
gedownload, alstublieft bevestigt dat het programma downloadt\n\
aan de plaats bovenstaande bestaat specificeerde en uitvoerbaar\n\
is.\n",
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Baixe Fracassado",
		    s,
"O comando baixava o objeto não podia ser executado, por favor\n\
verifica-se que o programa de download existe na localidade\n\
especificado acima e está executable.\n",
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Download Sviktet",
		    s,
"Kommandoen som brukt til download objektet ikke utfører, vær\n\
så snill og bekreft at download program finnes på plasseringen\n\
spesifisert ovenfor og er gjennomførbar.\n",
#else
"Download Failed",
		    s,
"The command used to download the object could not be executed,\n\
please verify that the download program exists at the location\n\
specified above and is executable.\n",
#endif
		    CDIALOG_ICON_ERROR,
		    CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP,
		    CDIALOG_BTNFLAG_OK
		);
		CDialogSetTransientFor(NULL);
		g_free(s);
		status = 1;
	    }
	    else
	    {
		gint edv_history_status = 0;
		gulong end_time;

		/* Download command executed, now monitor the download
	         * and handle the result
		 */
		const gint download_status = DownloadMonitor(
		    ctx, p, check_interval_ms,
		    source_url, destination_file, stdout_file,
		    geometry_flags,
		    geometry
		);

		/* Get the ending time of the download */
		end_time = (gulong)time(NULL);

		/* Check the result of the download */
		switch(download_status)
		{
		  case 0:	/* Success */
		    if(beep_when_complete)
			EDVPlaySoundCompleted(ctx);
		    if(open_object)
		    {
			GList *paths_list = NULL;
			paths_list = g_list_append(
			    paths_list, STRDUP(destination_file)
			);
			EDVOpen(ctx, paths_list, NULL);
			g_list_foreach(paths_list, (GFunc)g_free, NULL);
			g_list_free(paths_list);
		    }
		    edv_history_status = 0;
		    break;

		  case -2:	/* Process exited but object not completely downloaded */
		    if(beep_when_complete)
			EDVPlaySoundCompleted(ctx);
		    status = 2;
		    edv_history_status = -1;
		    break;

		  case -3:	/* Object not downloaded (does not exist) */
		    status = 2;
		    edv_history_status = -2;
		    break;

		  case -4:	/* User abort */
		    status = 4;
		    edv_history_status = -4;
		    break;
		}

		/* Record the last downloaded URL regardless of the
		 * above result
		 */
		DownloadCFGSetLast(
		    ctx, source_url, destination_path, download_status
		);

		/* Append history to Endeavour */
		EDVHistoryAppend(
		    ctx,
		    EDV_HISTORY_DISK_OBJECT_DOWNLOAD,
		    start_time, end_time,
		    edv_history_status,
		    source_url,
		    destination_path,
		    NULL		/* No comments */
		);
	    }
	}	/* Execute the download program and monitor the download */


	DO_SHUTDOWN

	return(status);
#undef DO_SHUTDOWN
}
