Index: /trunk/gli/src/org/greenstone/gatherer/download/Download.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/download/Download.java	(revision 12529)
+++ /trunk/gli/src/org/greenstone/gatherer/download/Download.java	(revision 12529)
@@ -0,0 +1,290 @@
+/**
+ *#########################################################################
+ *
+ * A component of the Gatherer application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: John Thompson, Greenstone Digital Library, University of Waikato
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * 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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *########################################################################
+ */
+package org.greenstone.gatherer.download;
+
+import java.io.*;
+import java.util.*;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+import org.w3c.dom.*;
+import org.greenstone.gatherer.cdm.*;
+
+/** This class is responsible for storing information from a parsed classinfo.pl call in such a way that it allows easy access to parsed details for the purposes of user design and specification of downloads.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class Download  extends ArgumentContainer
+    {
+
+    static final public String DOWNLOAD_PREFIX = "CL";
+
+    private boolean is_abstract = false;
+
+    /** A reference to the download that this one inherits from. */
+    private Download super_download = null;
+    /** The element this download is based upon. */
+    private Element element;
+    /** A description of this download. */
+    private String description = null;
+    /** The name of the download as it would appear in the collect.cfg file. */
+    private String name = null;
+    /** This string is filled out the first time this download is created, and remains unchanged there-after. It is used to match up with Format commands that may not yet have been instantiated (and thus only have offline references along the lines of 'CL1' to figure out what Download they want.) */
+    private String old_position_string = null;
+
+    /** Constructor used only in DOMProxyListModel initializations.
+     */
+    public Download() {
+    }
+
+    /** Method to add an argument to this download. Only adds the argument if it isn't already present.
+     * @param argument The <strong>Argument</strong> to add.
+     */
+    public void addArgument(Argument argument) {
+	if(element == null && !contains(argument)) {
+	    add(argument);
+	    argument.setOwner(name);
+	}
+    }
+
+    /** Method to compare two downloads for ordering.
+     * @param object The download we are comparing to, as an <strong>Object</strong>.
+     * @return An <i>int</i> specifying the download order, using values as set out in String.
+     * @see java.lang.String#compareTo
+     */
+    public int compareTo(Object object) {
+	if(object == null) {
+	    return -1;
+	}
+	return toString().compareTo(object.toString());
+    }
+
+     /** The assigned download constructor.
+      * @param element the DOM Element this classifier is based upon
+     */
+    public DOMProxyListEntry create(Element element) {
+// 	String download_name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
+// 	// Determine the base classifier from the classifier name
+// 	Classifier base_classifier = CollectionDesignManager.classifier_manager.getBaseClassifier(classifier_name);
+// 	Classifier classifier = new Classifier(element, base_classifier);
+// 	base_classifier = null;
+// 	classifier_name = null;
+// 	return classifier;
+	return null;
+    }
+
+    /** Method to determine if two downloads are equal.
+     * @param object The download to test against, as an <strong>Object</strong>.
+     * @return <i>true</i> if the download names match, <i>false</i> otherwise.
+     */
+    public boolean equals(Object object) {
+	return (compareTo(object) == 0);
+    }
+
+    /** Method to retrieve an argument by its name.
+     * @param name The name of the argument as a <strong>String</strong>.
+     * @return The <strong>Argument</strong> requested, or <i>null</i> if no such argument.
+     */
+    public Argument getArgument(String name) {
+	// The name given may still include the '-'
+	if(name.startsWith("-")) {
+	    name = name.substring(1);
+	}
+	ArrayList arguments = getArguments(true, true);
+	for(int i = 0; i < arguments.size(); i++) {
+	    Argument argument = (Argument)arguments.get(i);
+	    if(argument.getName().equals(name)) {
+		return argument;
+	    }
+	}
+	return null;
+    }
+
+     /** Retrieve all of the arguments available to this base download, including its super downloads arguments. Some complexity is added by allowing the caller to choose whether they want normal arguments, custom arguments, or both.
+      * @return an ArrayList of all of the arguments, starting with those for this download and ending with the arguments for basplug or similiar root download
+      */
+    public ArrayList getArguments(boolean include_normal, boolean include_custom) {
+	ArrayList arguments = new ArrayList();
+	if(include_normal && include_custom) {
+	    arguments.addAll(this);
+	}
+	else {
+	    int size = size();
+	    for(int i = 0; i < size; i++) {
+		Argument argument = (Argument) get(i);
+		if(argument.isCustomArgument()) {
+		    if(include_custom && !arguments.contains(argument)) {
+			arguments.add(argument);
+		    }
+		}
+		else {
+		    if(include_normal && !arguments.contains(argument)) {
+			arguments.add(argument);
+		    }
+		}
+		argument = null;
+	    }
+	}
+	if(super_download != null) {
+	    ArrayList remainder = super_download.getArguments(include_normal, include_custom);
+	    remainder.removeAll(arguments);
+	    arguments.addAll(remainder);
+	}
+	return arguments;
+    }
+
+    /** Method to retrieve a download custom argument information. Custom arguments are defined to be those that have not got matching arguments in the base reference download from the library. Of course if there is no base download then all arguments are considered to be custom.
+     * @return the custom arguments as a String
+     */
+    public String getCustom() {
+	StringBuffer custom_text = new StringBuffer();
+	// Retrieve all of the arguments, and append any that are custom into one long string
+	ArrayList arguments = getArguments(false, true);
+	int arguments_size = arguments.size();
+	boolean first = true;
+	for(int i = 0; i < arguments_size; i++) {
+	    Argument argument = (Argument) arguments.get(i);
+	    if(argument.isAssigned()) {
+		if(!first) {
+		    custom_text.append(" ");
+		}
+		custom_text.append(argument.toString());
+		first = false;
+	    }
+	}
+	return custom_text.toString();
+    }
+
+    public String getDescription() {
+	return description;
+    }
+
+    public Element getElement() {
+	return element;
+    }
+
+    /** Method to retrieve a download name.
+     * @return A <strong>String</strong> containing the downloads name.
+     */
+    public String getName() {
+	if(name == null && element != null) {
+	    name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
+	}
+	return name;
+    }
+
+    public boolean isAbstract() {
+	return is_abstract;
+    }
+
+    public boolean isAssigned() {	
+	return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
+    }
+
+    public void setAssigned(boolean assigned) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+	}
+    }
+
+    /** Set the custom arguments. This turns out to be quite tricky. We must parse in the string, searching for arguments (for that we use a handy method in CollectionConfiguration). Next, for each argument, we check if we already know about it. If so we update its value, otherwise we create a new argument and assign it (must assign!).
+     * @param custom_str the custom arguments all splodged together in one String
+     */
+    public void setCustom(String custom_str) {
+	HashMap raw_arguments = CollectionConfiguration.parseArguments(new CommandTokenizer(custom_str));
+	ArrayList custom_arguments = getArguments(false, true);
+	int size = custom_arguments.size();
+	for(int i = 0; i < size; i++) {
+	    Argument argument = (Argument) custom_arguments.get(i);
+	    String original_argument_name = StaticStrings.MINUS_CHARACTER + argument.getName();
+	    if(raw_arguments.containsKey(original_argument_name)) {
+		// Set as assigned
+		argument.setAssigned(true);
+		String argument_value = (String)raw_arguments.remove(original_argument_name);
+		if(argument_value != null) {
+		    argument.setValue(argument_value);
+		    argument_value = null;
+		}
+	    }
+	    // We've removed it from our custom statement, so unassign
+	    else {
+		argument.setAssigned(false);
+	    }
+	    argument = null;
+	}
+	// Any left over, add to the download
+	Iterator argument_names = raw_arguments.keySet().iterator();
+	while(argument_names.hasNext()) {
+	    String argument_name = (String) argument_names.next();
+	    String argument_value = (String) raw_arguments.get(argument_name);
+	    // The tricky thing is that we have to create a new element in the DOM as well.
+	    Element argument_element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.OPTION_ELEMENT);
+	    argument_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, argument_name.substring(1));
+	    argument_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
+	    argument_element.setAttribute(StaticStrings.CUSTOM_ATTRIBUTE, StaticStrings.TRUE_STR);
+	    Argument argument = new Argument(argument_element);
+	    argument_name = null;
+	    if(argument_value != null) {
+		argument.setValue(argument_value);
+		argument_value = null;
+	    }
+	    // All done. Add it.
+	    element.appendChild(argument_element);
+	    add(argument);
+	    argument_element = null;
+	}
+	raw_arguments = null;
+    }
+
+    /** Method to set the value of desc.
+     * @param description The new value of desc as a <strong>String</strong>.
+     */
+    public void setDescription(String description) {
+	this.description = description;
+    }
+
+    public void setElement(Element element) {
+	this.element = element;
+    }
+
+    public void setIsAbstract(boolean is_abstract) {
+	this.is_abstract = is_abstract;
+    }
+
+    /** Method to set the value of name.
+     * @param name The new value of name as a <strong>String</strong>.
+     */
+    public void setName(String name) {
+	this.name = name;
+    }
+
+    /** Method to set the value of the super_download.
+     * @param super_download The new value of super_download as a <strong>Download</strong>, or <i>null</i> if this class has no inheritance.
+     */
+    public void setSuper(Download super_download) {
+	this.super_download = super_download;
+    }
+}
Index: /trunk/gli/src/org/greenstone/gatherer/download/DownloadJob.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/download/DownloadJob.java	(revision 12529)
+++ /trunk/gli/src/org/greenstone/gatherer/download/DownloadJob.java	(revision 12529)
@@ -0,0 +1,492 @@
+/**
+ *#########################################################################
+ *
+ * A component of the Gatherer application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Author: John Thompson, Greenstone Digital Library, University of Waikato
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * 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.
+ *
+ * <BR><BR>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *########################################################################
+ */
+package org.greenstone.gatherer.download;
+
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.GAuthenticator;
+import org.greenstone.gatherer.LocalGreenstone;
+import org.greenstone.gatherer.file.WorkspaceTree;
+import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
+import org.greenstone.gatherer.util.GURL;
+import org.greenstone.gatherer.util.SynchronizedTreeModelTools;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.cdm.Argument;
+import org.greenstone.gatherer.collection.*;
+/**
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.0
+ */
+public class DownloadJob
+    implements ActionListener {
+	 
+    private boolean debug;
+    private boolean higher_directories;
+    private boolean no_parents;
+    private boolean other_hosts; 
+    private boolean page_requisites; 
+    private boolean quiet;
+
+    private AppendLineOnlyFileDocument download_log;
+
+    private DownloadProgressBar progress;
+
+    private GURL initial = null;
+    private GURL url = null;
+
+   
+    // private TreeModel model;
+
+    private int depth;
+    private int previous_state;
+    private int state;
+
+    private String download_url = "";
+
+    //    private String current_url;
+    //    private String destination;
+    private String proxy_pass;
+    private String proxy_user;
+
+    private Vector encountered_urls;
+    private Vector failed_urls;
+    private Download download;
+    private DownloadScrollPane mummy;
+    private HashMap download_option;
+
+    public static int COMPLETE = 0;
+    public static int PAUSED   = 1;
+    public static int RUNNING  = 2;
+    public static int STOPPED  = 3;
+
+    public static int UNKNOWN_MAX  = 0;
+    public static int DEFINED_MAX  = 1;
+    public static int UNDEFINED_MAX  = 2;
+
+    private String mode = null;
+   
+    private String proxy_url;
+
+    /**
+     */
+    public DownloadJob(Download download, String proxy_pass, String proxy_user, DownloadScrollPane mummy, String mode, String proxy_url) {
+	URL url = null;
+	int folder_hash;
+
+        this.proxy_url =  proxy_url;
+	
+       	download_option = downloadToHashMap(download);
+	if (!mode.equals("Z3950") && !mode.equals("SRW")) {
+	    Argument url_arg = (Argument)download_option.get((String)"url");
+	    download_url =  url_arg.getValue();
+	    
+	}
+	else {
+	    Argument host_arg = (Argument)download_option.get((String)"host");
+	    Argument port_arg = (Argument)download_option.get((String)"port");
+	    download_url = host_arg.getValue() + ":" +port_arg.getValue();
+	}
+       
+	folder_hash = download_url.hashCode();
+	String log_filename = Utility.getLogDir(null) + "download-"+ mode + folder_hash + ".log";
+	File log_file = new File(log_filename);
+	if(log_file.exists()) {
+	    log_file.delete();
+	}
+
+	File parent_log_file = log_file.getParentFile();
+	parent_log_file.mkdirs();
+	parent_log_file = null;
+	log_file = null;
+
+	this.download_log = new AppendLineOnlyFileDocument(log_filename, false);
+   
+	this.proxy_pass = proxy_pass;
+	this.proxy_user = proxy_user;
+	this.mummy = mummy;
+	this.mode = mode;
+	this.download = download;
+
+	progress = new DownloadProgressBar(this,download_url, true);
+	encountered_urls = new Vector();
+	failed_urls = new Vector();
+
+	previous_state = STOPPED;
+	state = STOPPED;
+    }
+
+    private HashMap downloadToHashMap(Download download)
+    {
+	HashMap download_option = new HashMap();
+	ArrayList arguments = download.getArguments(true, false);
+	for(int i = 0; i < arguments.size(); i++) {
+	    Argument argument = (Argument) arguments.get(i);
+	    download_option.put(argument.getName(), argument);
+	}
+	return download_option;
+    }
+
+    /** Depending on which button on the progress bar was pushed,
+     * this method will affect the state of the DownloadJob and perhaps make
+     * calls to wget.class if necessary.
+     * @param event The ActionEvent fired from within the DownloadProgressBar
+     * which we must respond to.
+     */
+    public void actionPerformed(ActionEvent event) {
+	// The stop_start_button is used to alternately start or stop the
+	// job. If the current state of the job is paused then this
+	// restart is logically equivelent to a resume.
+	if(event.getSource() == progress.stop_start_button) {
+	    previous_state = state;
+	    if (state == RUNNING) {
+		state = STOPPED;
+	    } else {
+		//previous_state = state;
+		state = RUNNING;
+		mummy.resumeThread();
+	    }
+	}
+	else if (event.getSource() == progress.close_button) {
+	    if(state == RUNNING) {
+		previous_state = state;
+		state = STOPPED; // do we need to do anything else to stop this?
+	    } 
+	    mummy.deleteDownloadJob(this);
+	}
+    }
+
+
+    public void callDownload() {
+	
+	ArrayList command_list = new ArrayList();
+        if (Utility.isWindows()) {
+	    command_list.add(Configuration.perl_path);
+	    command_list.add("-S");
+	}
+	command_list.add(LocalGreenstone.getBinScriptDirectoryPath()+"downloadfrom.pl");
+	command_list.add("-download_mode");
+	command_list.add(mode);
+	command_list.add("-cache_dir");
+
+	String user_home = System.getProperty("user.home");      
+	if (Utility.isWindows()){
+	    command_list.add(user_home + File.separator+"gli"+File.separator + "cache");
+	}
+	else{
+	    command_list.add(user_home + File.separator+".gli"+File.separator +"cache");
+	}
+	
+	ArrayList all_arg = download.getArguments(true,false);
+	for(int i = 0; i < all_arg.size(); i++) {
+	    Argument argument = (Argument) all_arg.get(i);
+	    if(argument.isAssigned()) {
+		command_list.add("-" + argument.getName());
+		if(argument.getType() != Argument.FLAG) {
+		    command_list.add(argument.getValue());
+		}
+	    }   
+	}
+
+	String [] cmd = (String []) command_list.toArray(new String[0]);
+	DebugStream.println("Download job, "+command_list);
+
+	if (previous_state == DownloadJob.COMPLETE) {
+	    progress.mirrorBegun(true, true);
+	}
+	else {
+	    progress.mirrorBegun(false, true);
+	}
+
+	try {
+	    Runtime rt = Runtime.getRuntime();
+
+	    String [] env = null;
+	 
+	    Process prcs = null; 
+
+         
+	    if (Utility.isWindows()) {
+              	prcs = rt.exec(cmd);   
+	    }
+	    else {
+		if (proxy_url != null && !proxy_url.equals("")) {          	
+		    env = new String[4];
+                    proxy_url = proxy_url.replaceAll("http://","");
+		    env[0] = "http_proxy=http://"+proxy_url;
+		    env[1] = "ftp_proxy=ftp://"+proxy_url;
+		    env[2] = "GSDLHOME="+Configuration.gsdl_path;
+		    env[3] = "GSDLOS="+System.getProperty("os.name");
+		    prcs = rt.exec(cmd,env); 
+		} 
+		else {		 
+		    env = new String[2];
+		 
+		    env[0] = "GSDLHOME="+Configuration.gsdl_path;
+		    env[1] = "GSDLOS="+System.getProperty("os.name");
+		    prcs = rt.exec(cmd,env); 
+		} 
+		
+	    }
+ 
+	    //System.out.println(newcmd);	    
+
+	    InputStreamReader isr = new InputStreamReader(prcs.getErrorStream());
+	    BufferedReader br = new BufferedReader(isr);
+	    // Capture the standard error stream and seach for two particular occurances.
+	    String line="";
+	    boolean ignore_for_robots = false;
+	    int max_download = DownloadJob.UNKNOWN_MAX;
+
+
+	    while ((line = br.readLine()) != null && !line.trim().equals("<<Finished>>") && state != STOPPED) {
+
+		if ( max_download == DownloadJob.UNKNOWN_MAX) {
+		    if(line.lastIndexOf("<<Defined Maximum>>") != -1) {
+			max_download = DownloadJob.DEFINED_MAX;
+		    }
+		    else if (line.lastIndexOf("<<Undefined Maximum>>") != -1) {
+			max_download = DownloadJob.UNDEFINED_MAX;
+		    }
+		}
+		else if(max_download == DownloadJob.UNDEFINED_MAX) {
+		    DebugStream.println(line);
+		    download_log.appendLine(line);
+		    // The first magic special test is to see if we've just
+		    // asked for the robots.txt file. If so we ignore
+		    // the next add and then the next complete/error.
+		    if(line.lastIndexOf("robots.txt;") != -1) {
+			DebugStream.println("***** Requesting robot.txt");
+			ignore_for_robots = true;
+		    }
+		    // If line contains "=> `" display text as the 
+		    // currently downloading url. Unique to add download.
+		    else if(line.lastIndexOf("=> `") != -1) {
+			if(!ignore_for_robots) {
+			    // Add download
+			    String new_url = line.substring(line.indexOf("`") + 1, line.lastIndexOf("'"));
+			    //addDownload("http:/" + new_url);
+			}
+		    }
+		    // If line contains "/s) - `" set currently 
+		    // downloading url to "Download Complete".
+		    else if(line.lastIndexOf("/s) - `") != -1) {
+			String current_file_downloading = line.substring(line.indexOf("`") + 1, line.lastIndexOf("'"));
+			if(!ignore_for_robots) {
+			    DebugStream.println("Not ignore for robots");
+			    // Download complete
+			    downloadComplete(current_file_downloading);
+			}
+			else {
+			    DebugStream.println("Ignore for robots");
+			    ignore_for_robots = false;
+			}
+		    }
+		    // The already there line begins "File `..." However this
+		    // is only true in english, so instead I looked and there
+		    // are few (if any at all) other messages than those above
+		    // and not overwriting messages that use " `" so we'll 
+		    // look for that. Note this method is not guarenteed to be
+		    // unique like the previous two.
+		    else if(line.lastIndexOf(" `") != -1) {
+			// Not Overwriting
+			DebugStream.println("Already there.");
+			String new_url = 
+			    line.substring(line.indexOf("`") + 1, line.lastIndexOf("'"));
+			//addDownload("http:/" + new_url);
+			downloadWarning();
+		    }
+		    // Any other important message starts with the time in the form hh:mm:ss
+		    else if(line.length() > 7) {
+			if(line.charAt(2) == ':' && line.charAt(5) == ':') {
+			    if(!ignore_for_robots) {
+				DebugStream.println("Error.");
+				downloadFailed();
+			    }
+			    else {
+				ignore_for_robots = false;
+			    }
+			}
+		    }
+		}
+		else if (max_download == DownloadJob.DEFINED_MAX) {
+		    if (line.lastIndexOf("<<Total number of record(s):") != -1) {
+			String total_ID = line.substring(line.indexOf(":") + 1, line.indexOf(">"));
+			progress.setTotalDownload((Integer.valueOf(total_ID)).intValue());
+			progress.resetFileCount();
+		    }
+		    else if (line.lastIndexOf("<<Done>>") != -1) {
+			progress.increaseFileCount();
+		    }
+		    else if(line.lastIndexOf("<<Done:") != -1) {
+			String completed_amount = line.substring(line.indexOf(":") + 1, line.indexOf(">"));
+			progress.increaseFileCount((Integer.valueOf(completed_amount)).intValue());
+		    }
+		    
+		    DebugStream.println(line);
+		    download_log.appendLine(line);
+		}
+		else {
+		    System.out.println("Error!!");
+		    System.exit(-1);
+		}
+	    }
+	    if(state == STOPPED) {
+		isr.close();
+		prcs.destroy(); // This doesn't always work, but it's worth a try
+	    }
+	   
+	}
+	catch (Exception ioe) {
+	    //message(Utility.ERROR, ioe.toString());
+	    //JTest
+	    DebugStream.printStackTrace(ioe);
+	}
+	// If we've got to here and the state isn't STOPPED then the
+	// job is complete.
+	if(state == DownloadJob.RUNNING) {
+	    progress.mirrorComplete();
+	    previous_state = state;
+	    state = DownloadJob.COMPLETE;
+	    
+	}
+	// refresh the workspace tree
+ 	Gatherer.g_man.refreshWorkspaceTree(WorkspaceTree.DOWNLOADED_FILES_CHANGED);
+       
+    }
+
+
+    /** Called by the WGet native code when the current download is 
+     * completed. In turn all download listeners are informed.
+     */
+    public void downloadComplete() {
+	progress.downloadComplete();
+    }
+
+
+    public void downloadComplete(String current_file_downloading)
+    {
+	progress.downloadComplete();
+	DebugStream.println("Download complete: " + current_file_downloading);
+    }
+
+
+    /** Called by the WGet native code when the requested download returns
+     * a status code other than 200.
+     */
+    public void downloadFailed() {
+	// TODO!!
+	//failed_urls.add(current_url); // It is the current url that failed
+	progress.downloadFailed();
+	//DebugStream.println("Download failed: " + current_url);
+    } 
+	 
+    /**
+     */
+    public void downloadWarning() {
+	progress.downloadWarning();
+    }
+
+
+    /** 
+     * @return A String representing the initial urls host (root node
+     * of tree that we are mirroring).
+     */
+    public String getHost() {
+	return url.getHost();
+    }
+
+    public AppendLineOnlyFileDocument getLogDocument() {
+	return download_log;
+    }
+
+    /**
+     * @return Returns the progress bar associated with this job.
+     */
+    public DownloadProgressBar getProgressBar() {
+	return progress;
+    }
+
+    /** Called to discover if the user wanted this thread to run or if
+     * it is paused.
+     * @return An int representing the current DownloadJob state.
+     */
+    public int getState() {
+	return state;
+    }
+
+    /** Returns the current state of the stop flag for this job.
+     * @return A boolean representing whether the user has requested to
+     * stop.
+     */
+    public boolean hasSignalledStop() {
+	if(state == DownloadJob.STOPPED || state == DownloadJob.PAUSED || 
+	   state == DownloadJob.COMPLETE) {
+	    return true;
+	}
+	return false;
+    }
+
+    public void setState(int state) {
+	previous_state = this.state;
+	this.state = state;
+    }
+
+    /** A convenience call.
+     * @return A String representing the url of the initial url (root node of the mirrored tree).
+     */
+    public String toString() {
+	return download_url;
+    }
+
+    /** Called by the WGet native code to signal the current progress of 
+     * downloading.
+     * @param current A long representing the number of bytes that have 
+     * been downloaded since the last update. 
+     * @param expected A long representing the total number of bytes
+     * expected for this download.
+     */
+    public void updateProgress(long current, long expected) {
+	progress.updateProgress(current, expected);
+    }
+}
Index: /trunk/gli/src/org/greenstone/gatherer/download/DownloadProgressBar.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/download/DownloadProgressBar.java	(revision 12529)
+++ /trunk/gli/src/org/greenstone/gatherer/download/DownloadProgressBar.java	(revision 12529)
@@ -0,0 +1,421 @@
+/**
+ *#########################################################################
+ *
+ * A component of the Gatherer application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Author: John Thompson, Greenstone Digital Library, University of Waikato
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * 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.
+ *
+ * <BR><BR>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *########################################################################
+ */
+package org.greenstone.gatherer.download;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+//import org.greenstone.gatherer.collection.DownloadJob;
+import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.gui.*;
+
+public class DownloadProgressBar
+    extends JPanel 
+    implements ActionListener {
+
+    private boolean simple = false;
+
+    private Dimension bar_size = new Dimension(520, 25);
+
+    private Dimension MINIMUM_BUTTON_SIZE = new Dimension(100, 25);
+    private  Dimension PROGRESS_BAR_SIZE = new Dimension(580,75);
+    
+    private int current_action;
+    private int err_count;
+    private int file_count;
+    private int total_count;
+    private int warning_count;
+
+    private JLabel current_status;
+    private JLabel main_status;
+    private JLabel results_status;
+	 
+    private JPanel center_pane;
+    private JPanel inner_pane;
+
+    private JProgressBar progress;
+
+    private long file_size;
+    private long total_size;
+
+    private String current_url;
+    private String initial_url;
+
+    private DownloadJob owner;
+
+    public JButton stop_start_button;
+    public JButton log_button;
+    public JButton close_button;
+
+    public DownloadProgressBar(DownloadJob owner, String initial_url, boolean simple) {
+	this.owner = owner;
+	this.current_url = null;
+	this.err_count = 0;
+	this.initial_url = initial_url;
+	this.file_count = 0;
+	this.file_size = 0;
+	this.simple = simple;
+	this.total_count = 0;
+	this.total_size = 0;
+	this.warning_count = 0;
+
+	this.setLayout(new BorderLayout());
+	this.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
+
+	this.current_action = DownloadJob.STOPPED;
+
+	inner_pane = new JPanel(new BorderLayout());
+	inner_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
+
+	center_pane = new JPanel(new GridLayout(3,1));
+
+	main_status = new JLabel();
+
+	current_status = new JLabel();
+		  
+	results_status = new JLabel();
+
+	progress = new JProgressBar();
+	progress.setStringPainted(true);
+	progress.setMinimum(0);
+	progress.setMaximum(0);
+	progress.setEnabled(false);
+	progress.setString(Dictionary.get("Mirroring.DownloadJob.Waiting"));
+	inner_pane.add(progress, BorderLayout.CENTER);
+
+	center_pane.add(main_status);
+	center_pane.add(current_status);
+	center_pane.add(results_status);
+
+	JPanel button_pane = new JPanel();
+
+	stop_start_button = new GLIButton(Dictionary.get("Mirroring.DownloadJob.Pause"),Dictionary.get("Mirroring.DownloadJob.Pause_Tooltip"));
+	stop_start_button.addActionListener(this);
+	stop_start_button.addActionListener(owner);
+	stop_start_button.setMinimumSize(MINIMUM_BUTTON_SIZE);
+	stop_start_button.setMnemonic(KeyEvent.VK_P);
+	stop_start_button.setEnabled(true);
+	
+
+	log_button = new GLIButton(Dictionary.get("Mirroring.DownloadJob.Log"),Dictionary.get("Mirroring.DownloadJob.Log_Tooltip"));
+	log_button.addActionListener(owner);
+	log_button.addActionListener(this);
+	log_button.setEnabled(false);
+	log_button.setMinimumSize(MINIMUM_BUTTON_SIZE);
+	log_button.setMnemonic(KeyEvent.VK_L);
+
+
+	close_button =  new GLIButton(Dictionary.get("Mirroring.DownloadJob.Close"),Dictionary.get("Mirroring.DownloadJob.Close_Tooltip"));
+	close_button.addActionListener(owner);
+	close_button.addActionListener(this);
+	close_button.setMinimumSize(MINIMUM_BUTTON_SIZE);
+	close_button.setMnemonic(KeyEvent.VK_C);
+	close_button.setEnabled(true);
+
+
+	// Layout - or at least some of it
+
+	inner_pane.add(center_pane, BorderLayout.NORTH);
+
+	button_pane.setLayout(new GridLayout(3,1));
+	button_pane.add(stop_start_button);
+	button_pane.add(log_button);
+	button_pane.add(close_button);
+
+	this.add(inner_pane, BorderLayout.CENTER);
+	this.add(button_pane, BorderLayout.EAST);
+
+	// Make the labels, etc update.
+	refresh();
+    }
+
+    public void actionPerformed(ActionEvent event) {
+	Object source = event.getSource();
+	if(source == stop_start_button) {
+	    // If we are running, stop.
+	    if (current_action == DownloadJob.RUNNING) {
+		current_action = DownloadJob.STOPPED;
+                stop_start_button.setText(Dictionary.get("Mirroring.DownloadJob.Resume"));
+                stop_start_button.setToolTipText(Dictionary.get("Mirroring.DownloadJob.Resume_Tooltip"));
+	        
+		progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Stopped"));
+		progress.setIndeterminate(false);
+	    } else {
+		current_action = DownloadJob.RUNNING;
+		// we are stopped, so restart
+                stop_start_button.setText(Dictionary.get("Mirroring.DownloadJob.Pause"));
+                stop_start_button.setToolTipText(Dictionary.get("Mirroring.DownloadJob.Pause_Tooltip"));
+		progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Progress"));
+		progress.setIndeterminate(true);
+	    }
+	}
+	else if(source == close_button) {
+	    // If we are running, stop.
+	    if (current_action == DownloadJob.RUNNING) {
+		current_action = DownloadJob.STOPPED;
+             	progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Stopped"));
+	
+		progress.setIndeterminate(false);
+	    }
+	}
+	else if(source == log_button) {
+           
+	    LogDialog dialog = new LogDialog(owner.getLogDocument());
+	    dialog.setVisible(true);
+	    dialog = null;
+	}
+
+	refresh();
+    }
+
+    /** This method is called when a new download is begun. The
+     * details of the download are updated and a new JProgressBar
+     * assigned to track the download.
+     * @param url The url String of the file that is being downloaded.
+     */
+    public void addDownload(String url) {
+	current_url = url;
+	file_size = 0;
+	refresh();
+    }
+
+    /** When the download of the current url is completed, this method
+     * is called to enlighten the DownloadProgressBar of this fact.
+     */
+    public void downloadComplete() {
+	current_url = null;
+	file_count++;
+	if(total_count < (file_count + err_count + warning_count)) {
+	    total_count = (file_count + err_count + warning_count);
+	}
+	progress.setValue(progress.getMaximum());
+	//Dictionary.setText(progress, "Mirroring.DownloadJob.Download_Complete");
+	refresh();
+    }
+
+    public void downloadFailed() {
+	err_count++;
+	if(total_count < (file_count + err_count + warning_count)) {
+	    total_count = (file_count + err_count + warning_count);
+	}
+	refresh();
+    }
+
+    public void downloadWarning() {
+	warning_count++;
+	if(total_count < (file_count + err_count + warning_count)) {
+	    total_count = (file_count + err_count + warning_count);
+	}
+	refresh();
+    }
+
+    public void setTotalDownload(int total_download) {
+	total_count = total_download;
+	refresh();
+    }
+
+    public Dimension getPreferredSize() {
+	return PROGRESS_BAR_SIZE;
+    }
+
+    public void increaseFileCount() {
+	file_count++;
+	refresh();
+    }
+
+    public void increaseFileCount(int amount) {
+	file_count += amount;
+	refresh();
+    }
+
+    public void resetFileCount() {
+	file_count = 0;
+	refresh();
+    }
+
+    /** When a mirroring task is first initiated this function is called
+     * to set initial values for the variables if necessary and to 
+     * fiddle visual components such as the tool tip etc.
+     * @param reset A Boolean specifying whether the variables should be
+     * reset to zero.
+     */
+    public void mirrorBegun(boolean reset, boolean simple) {
+	if(reset) {
+	    this.file_count = 0;
+	    this.file_size = 0;
+	    this.total_count = 0;
+	    this.total_size = 0;
+	    this.err_count = 0;
+	    this.warning_count = 0;
+	}
+	current_action = DownloadJob.RUNNING;
+	stop_start_button.setEnabled(true);
+	log_button.setEnabled(true);
+	if(simple) {
+	    progress.setIndeterminate(true);
+	    progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Progress"));
+	}
+    }	
+
+    /** Once a mirroring task is complete, is the DownloadJob returns from the
+     * native call but the status is still running, then this method
+     * is called to once again tinker with the pritty visual 
+     * components.
+     */
+    public void mirrorComplete() {
+	current_action = DownloadJob.COMPLETE;
+	current_url = null;
+	if(simple) {
+	    progress.setIndeterminate(false);
+	}
+	progress.setValue(progress.getMaximum());
+	progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Complete"));
+
+	stop_start_button.setEnabled(false);
+	this.updateUI();
+    }
+
+    /** When called this method updates the DownloadProgressBar to reflect
+     * the ammount of the current file downloaded.
+     */
+    public void updateProgress(long current, long expected) {
+	file_size = file_size + current;
+	if(!progress.isIndeterminate()) {
+	    // If current is zero, then this is the 'precall' before the
+	    // downloading actually starts.
+	    if(current == 0) {
+		// Remove the old progress bar, then deallocate it.
+		inner_pane.remove(progress);
+		progress = null;
+		if(expected == 0) {
+		    // We don't have a content length. This bar will go from 0 to 100 only!
+		    progress = new JProgressBar(0, 100);
+		}
+		else {
+		    // Assign a new progress bar of length expected content length.
+		    progress = new JProgressBar(0, (new Long(expected)).intValue());
+		}
+		progress.setEnabled(true);
+		// Add the new progress bar.
+		inner_pane.add(progress, BorderLayout.CENTER);
+		inner_pane.updateUI();
+	    }
+	    // Otherwise if expected is not zero move the progress bar and
+	    // update percent complete.
+	    else if (expected != 0) {
+		progress.setValue((new Long(file_size)).intValue());
+		int p_c = (new Double(progress.getPercentComplete() * 100)).intValue();
+		progress.setString(p_c + "%");
+		progress.setStringPainted(true);
+	    }
+	    // Finally, in the case we have no content length, we'll instead
+	    // write the current number of bytes downloaded again.
+	    else {
+		progress.setString(file_size + " b");
+		progress.setStringPainted(true);
+	    }
+	}
+	refresh();
+    }
+
+    /** Causes the two labels associated with this DownloadProgressBar object to
+     * update, thus reflecting the progression of the download. This 
+     * method is called by any of the other public setter methods in this 
+     * class.
+     */
+    private void refresh() {
+	// Refresh the contents of main label.
+	String args1[] = new String[1];
+	args1[0] = initial_url.toString();
+	main_status.setText(Dictionary.get("Mirroring.DownloadJob.Downloading", args1));
+
+	if (current_url != null) {
+	    // Refresh the current label contents.
+	    String args2[] = new String[1];
+	    args2[0] = current_url;
+	    current_status.setText(Dictionary.get("Mirroring.DownloadJob.Downloading", args2));
+	}
+	else if (current_action == DownloadJob.STOPPED || current_action == DownloadJob.PAUSED) {
+	    current_status.setText(Dictionary.get("Mirroring.DownloadJob.Waiting_User"));
+	}
+	else {
+	    current_status.setText(Dictionary.get("Mirroring.DownloadJob.Download_Complete"));
+	}
+
+	// Refresh the contents of results label
+	String args3[] = new String[4]; 
+	args3[0] = file_count + "";
+	args3[1] = total_count + "";
+	args3[2] = warning_count + "";
+	args3[3] = err_count + "";
+	results_status.setText(Dictionary.get("Mirroring.DownloadJob.Status", args3));
+
+	this.updateUI();
+    }
+
+    static final private Dimension DIALOG_SIZE = new Dimension(640,480);
+
+    private class LogDialog
+	extends JDialog {
+	
+	public LogDialog(AppendLineOnlyFileDocument document) {
+	    super(Gatherer.g_man, "Mirroring.DownloadJob.Download_Log_Dialog_Title");
+	    setSize(DIALOG_SIZE);
+	    JPanel content_pane = (JPanel) getContentPane();
+	    JTextArea text_area = new JTextArea(document);
+	    JButton button = new GLIButton(Dictionary.get("General.Close"));
+	    // Connection
+	    button.addActionListener(new CloseActionListener());
+	    // Layout
+	    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    content_pane.setLayout(new BorderLayout());
+	    content_pane.add(new JScrollPane(text_area), BorderLayout.CENTER);
+	    content_pane.add(button, BorderLayout.SOUTH);
+	}
+
+	private class CloseActionListener
+	    implements ActionListener {
+	    public void actionPerformed(ActionEvent event) {
+		LogDialog.this.dispose();
+	    }
+	}
+    }
+}
Index: /trunk/gli/src/org/greenstone/gatherer/download/DownloadScrollPane.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/download/DownloadScrollPane.java	(revision 12529)
+++ /trunk/gli/src/org/greenstone/gatherer/download/DownloadScrollPane.java	(revision 12529)
@@ -0,0 +1,225 @@
+/**
+ *#########################################################################
+ *
+ * A component of the Gatherer application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Author: John Thompson, Greenstone Digital Library, University of Waikato
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * 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.
+ *
+ * <BR><BR>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *########################################################################
+ */
+package org.greenstone.gatherer.download;
+
+import java.awt.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.*;
+
+/** This class provides access to the functionality of the WGet program, either by calling it via a shell script or by the JNI. It maintains a queue of pending jobs, and the component for showing these tasks to the user.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class DownloadScrollPane
+    extends Thread {
+    
+    /** <i>true</i> if there is a task currently being carried out, <i>false</i> otherwise. */
+    private boolean busy = false;
+    /** <i>true</i> if verbose debug messages should be displayed, <i>false</i> otherwise. */
+    private boolean debug = false;
+    /** <i>true</i> if successfully completed tasks should be automatically removed from the job queue. */
+    private boolean remove_complete_jobs = true;
+
+    private JPanel filler_pane = null;
+    /** The panel that the task list will be shown in. */
+    private JPanel list_pane;
+    /** The job currently underway. */
+    private DownloadJob job;
+    /** A scroll pane which will be used to display the list of pending tasks. */
+    private JScrollPane list_scroll;
+    /** A queue of download tasks. */
+    private Vector job_queue;
+    static final private boolean simple = true;
+    
+    public DownloadScrollPane() {
+	job = null;
+	job_queue = new Vector();
+	filler_pane = new JPanel();
+	list_pane = new JPanel();
+	list_pane.setLayout(new BoxLayout(list_pane, BoxLayout.Y_AXIS));
+	list_scroll = new JScrollPane(list_pane);
+    }
+
+    public void deleteDownloadJob(DownloadJob delete_me) {
+	if (delete_me == job) {
+	    while(busy) {
+	    }
+	    job = null;
+	}
+	if (delete_me.hasSignalledStop()) {
+	    list_pane.remove(delete_me.getProgressBar());
+	    job_queue.remove(delete_me);
+	    list_pane.remove(filler_pane);
+	    if(job_queue.size() > 0) {
+		Dimension progress_bar_size = delete_me.getProgressBar().getPreferredSize();
+		Dimension list_pane_size = list_pane.getSize();
+		int height = list_pane_size.height - (job_queue.size() * progress_bar_size.height);
+		progress_bar_size = null;
+		if(height > 0) {
+		    filler_pane.setPreferredSize(new Dimension(list_pane_size.width, height));
+		    list_pane.add(filler_pane);
+		}
+		list_pane_size = null;
+	    }
+	    list_pane.updateUI();
+	}
+	else {
+	    DebugStream.println("Somehow we're trying to delete a job that is still running.");
+	}
+    }
+
+    public synchronized void downloadComplete() {
+	job.downloadComplete();
+    }
+
+    public synchronized void downloadFailed() {
+	job.downloadFailed();
+    }
+
+    public synchronized void downloadWarning() {
+	job.downloadWarning();
+    }
+
+    public JScrollPane getDownloadJobList() {
+	return list_scroll;
+    }
+
+    public synchronized boolean hasSignalledStop() {
+	return job.hasSignalledStop();
+    }
+
+    public void newDownloadJob(Download download, String mode, String proxy_url) {
+	// Create the job and fill in the details from gatherer.config.
+
+	DebugStream.println("About to create a new job");
+
+
+        DownloadJob new_job = new DownloadJob(download, Configuration.proxy_pass, Configuration.proxy_user, this, mode, proxy_url);
+	// Tell it to run as soon as possible
+
+      
+
+	new_job.setState(DownloadJob.RUNNING);
+	
+	// Add to job_queue job list.
+	job_queue.add(new_job);
+
+	// Now add it to the visual component, job list.
+
+	list_pane.remove(filler_pane);
+
+	Dimension progress_bar_size = new_job.getProgressBar().getPreferredSize();
+
+	Dimension list_pane_size = list_pane.getSize();
+
+	int height = list_pane_size.height - (job_queue.size() * progress_bar_size.height);
+
+	progress_bar_size = null;
+
+	list_pane.add(new_job.getProgressBar());
+
+	if(height > 0) {
+	    filler_pane.setPreferredSize(new Dimension(list_pane_size.width, height));
+	    list_pane.add(filler_pane);
+	}
+
+	list_pane_size = null;
+	//list_pane.setAlignmentX(Component.LEFT_ALIGNMENT);
+	list_pane.updateUI();
+	new_job = null;
+	synchronized(this) {
+	    notify(); // Just incase its sleeping.
+	}
+    }
+    
+    public synchronized void updateProgress(long current, long expected) {
+	job.updateProgress(current, expected);
+    }
+    
+    /* There may be times when the download thread is sleeping, but the
+     * user has indicated that a previously paused job should now begin
+     * again. The flag within the job will change, so we tell the thread
+     * to start again.
+     */
+    public void resumeThread() {
+	synchronized(this) {
+	    notify(); // Just incase its sleeping.
+	}
+    }
+    
+    public void run() {
+	while(true) {
+	    if(job_queue.size() > 0) {
+		int index = 0;
+		while(job_queue.size() > 0 && index < job_queue.size()) {
+		    job = (DownloadJob) job_queue.get(index);
+		    if(job.getState() == DownloadJob.RUNNING) {
+			DebugStream.println("DownloadJob " + job.toString() + " Begun.");
+			busy = true;
+			job.callDownload();
+			busy = false;
+			DebugStream.println("DownloadJob " + job.toString() + " complete.");
+			job = null;
+		    }
+		    index++;
+		}
+		try {
+		    synchronized(this) {
+			DebugStream.println("WGet thread is waiting for DownloadJobs.");
+			wait();
+		    }
+		} catch (InterruptedException e) {
+		    // Time to get going again.
+		}
+	    }
+	    else {
+		try {
+		    synchronized(this) {
+			DebugStream.println("WGet thread is waiting for DownloadJobs.");
+			wait();
+		    }
+		} catch (InterruptedException e) {
+		    // Time to get going again.
+		}
+	    }
+	}
+    }
+}
Index: /trunk/gli/src/org/greenstone/gatherer/download/ServerInfoDialog.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/download/ServerInfoDialog.java	(revision 12529)
+++ /trunk/gli/src/org/greenstone/gatherer/download/ServerInfoDialog.java	(revision 12529)
@@ -0,0 +1,145 @@
+package org.greenstone.gatherer.download;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import java.io.*;
+import java.util.ArrayList;
+import org.greenstone.gatherer.cdm.Argument;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.LocalGreenstone;
+import org.greenstone.gatherer.gui.*;
+import org.greenstone.gatherer.util.Utility;
+
+public class ServerInfoDialog extends JDialog
+{    
+    static private Dimension SIZE = new Dimension(500, 300);
+    private String url;
+    private String mode;
+    private JPanel info_list_pane;
+    private JScrollPane info_scroll_pane;
+    private JDialog info_dialog;
+    private Download download;
+    private String proxy_url;
+    
+    public ServerInfoDialog(String url, String proxy_url, String mode, Download download) {
+	super();
+	this.url = url;
+	this.mode = mode;
+        this.download = download;
+        this.proxy_url = proxy_url;
+	this.info_dialog = this;
+	
+	this.setSize(SIZE);
+
+ 	JButton close_button = new GLIButton(Dictionary.get("General.Close"),Dictionary.get("General.Close_Tooltip"));
+ 	close_button.setEnabled(true); 
+	close_button.addActionListener(new ActionListener() {
+		public void actionPerformed(ActionEvent event) {
+		    info_dialog.dispose();
+		}
+	    });
+	
+	JPanel button_pane = new JPanel();
+	button_pane.setLayout(new FlowLayout());
+	button_pane.setBorder(BorderFactory.createEtchedBorder());
+	button_pane.add(close_button);
+	
+	info_list_pane = new JPanel();
+	info_list_pane.setLayout(new BoxLayout(info_list_pane, BoxLayout.Y_AXIS));
+	info_list_pane.setBorder(BorderFactory.createEtchedBorder());
+	getServerInfo();
+
+	info_scroll_pane = new JScrollPane(info_list_pane);
+	
+	JPanel information_pane = new JPanel();
+	information_pane.setLayout(new BorderLayout());
+	information_pane.setBorder(BorderFactory.createEtchedBorder());
+	information_pane.add(info_scroll_pane,BorderLayout.CENTER);
+	
+	JPanel main_pane = new JPanel();
+	main_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	main_pane.setLayout(new BorderLayout());
+	main_pane.add(information_pane,BorderLayout.CENTER);
+	main_pane.add(button_pane,BorderLayout.SOUTH);
+
+	Container main_container = this.getContentPane();
+	main_container.add(main_pane);
+	
+	// Show
+	Dimension screen_size = Configuration.screen_size;
+	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	setVisible(true);
+
+    }
+
+    private void getServerInfo()
+    {
+	ArrayList commands = new ArrayList();
+	if (Utility.isWindows()) {
+	    commands.add(Configuration.perl_path);
+	    commands.add("-S");
+	}
+	commands.add(LocalGreenstone.getBinScriptDirectoryPath()+"downloadfrom.pl");
+	commands.add("-info");
+	commands.add("-download_mode");
+	commands.add(mode);
+	
+       	ArrayList all_arg = download.getArguments(true,false);
+	for (int i = 0; i < all_arg.size(); i++) {
+	    Argument argument = (Argument) all_arg.get(i);
+	    
+	    if(argument.isAssigned()) {
+		commands.add("-" + argument.getName());
+		if(argument.getType() != Argument.FLAG) {
+		    commands.add(argument.getValue());
+		}
+	    }   
+	}
+	
+	String[] command = (String[]) commands.toArray(new String[0]);
+	DebugStream.println("Getting server info: "+commands);
+	try {
+	    String [] env = null;
+	    Process prcs = null; 
+	    Runtime rt = Runtime.getRuntime();
+	  
+	    if (Utility.isWindows()) {
+              	prcs = rt.exec(command);   
+	    }
+	    else {
+		ArrayList env_list = new ArrayList();
+		if (proxy_url != null && !proxy_url.equals("")) {          	
+                    proxy_url = proxy_url.replaceAll("http://","");
+		    env_list.add("http_proxy=http://"+proxy_url);
+		    env_list.add("ftp_proxy=ftp://"+proxy_url);
+		}
+		env_list.add("GSDLHOME="+Configuration.gsdl_path);
+		env_list.add("GSDLOS="+System.getProperty("os.name"));
+		env = (String []) env_list.toArray(new String[0]);
+		prcs = rt.exec(command,env); 
+		
+	    }
+
+	    InputStreamReader isr = new InputStreamReader(prcs.getErrorStream());
+	    BufferedReader br = new BufferedReader(isr);
+	    String line;
+	    // Capture the standard error stream and seach for two particular occurances.
+	    while ((line = br.readLine()) != null && !line.trim().equals("<<Finished>>")) {
+	      
+		JLabel a_label = new JLabel(line);
+		a_label.setAlignmentX(Component.LEFT_ALIGNMENT);
+		info_list_pane.add(a_label);
+	    }
+	    
+	} catch (Exception ioe) {
+	  
+	}
+	
+    }
+
+}
Index: /trunk/gli/src/org/greenstone/gatherer/gui/DownloadPane.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/gui/DownloadPane.java	(revision 12528)
+++ /trunk/gli/src/org/greenstone/gatherer/gui/DownloadPane.java	(revision 12529)
@@ -54,8 +54,8 @@
 import org.greenstone.gatherer.util.StaticStrings;
 import org.greenstone.gatherer.util.Utility;
-import org.greenstone.gatherer.cdm.download.*;
+import org.greenstone.gatherer.download.Download;
+import org.greenstone.gatherer.download.DownloadScrollPane;
+import org.greenstone.gatherer.download.ServerInfoDialog;
 import org.greenstone.gatherer.util.XMLTools;
-import org.greenstone.gatherer.cdm.download.DownloadScrollPane;
-import org.greenstone.gatherer.cdm.download.ServerInfoDialog;
 import org.greenstone.gatherer.cdm.*;
 import org.greenstone.gatherer.gui.*;
