source: debug-testing/gli_proxy/DownloadPane.java@ 31879

Last change on this file since 31879 was 31879, checked in by ak19, 7 years ago

Multiple proxy settings seems to be uncommon, and the default is that the proxy server is used for http, https, ftp. Documented with links in DownloadPane.java. The GUI portion for supporting multiple proxy fields been implemented in the modifications to Preferences.java, Gatherer.java and dictionary.props. The problem is in authentication in DownloadPane.java, don't we need to authenticate for each proxy setting? Having different proxy servers for different protocols seems to be an unusual/rare thing (as indicated in the links in DownloadPane.java) and the usual thing seems to be to use the http proxy server url for all three, including ftp. The proxy server protocol seems to have nothing to do with the outside protocol we're connecting to.

File size: 34.2 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.gui;
38
39import java.awt.*;
40import java.awt.event.*;
41import java.io.*;
42import java.net.*;
43import java.util.*;
44import javax.swing.*;
45import javax.swing.border.*;
46import javax.swing.event.*;
47import javax.swing.tree.*;
48import org.greenstone.gatherer.Configuration;
49import org.greenstone.gatherer.DebugStream;
50import org.greenstone.gatherer.Dictionary;
51import org.greenstone.gatherer.Gatherer;
52import org.greenstone.gatherer.file.WorkspaceTree;
53import org.greenstone.gatherer.greenstone.LocalGreenstone;
54import org.greenstone.gatherer.util.SafeProcess;
55import org.greenstone.gatherer.util.StaticStrings;
56import org.greenstone.gatherer.util.Utility;
57import org.greenstone.gatherer.download.URLConnectionManager;
58import org.greenstone.gatherer.download.Download;
59import org.greenstone.gatherer.download.DownloadScrollPane;
60import org.greenstone.gatherer.download.ServerInfoDialog;
61import org.greenstone.gatherer.util.XMLTools;
62import org.greenstone.gatherer.cdm.*;
63import org.greenstone.gatherer.gui.*;
64import org.w3c.dom.*;
65import org.xml.sax.*;
66import org.greenstone.gatherer.GAuthenticator;
67
68/**
69 * @author John Thompson, Greenstone Digital Library, University of Waikato
70 * @version 2.1
71 */
72public class DownloadPane
73 extends JPanel {
74
75 static final private Dimension LABEL_SIZE = new Dimension(225, 25);
76 static final private Dimension TREE_SIZE = new Dimension(150, 500);
77 //static final private String CONTENTS[] = { "DOWNLOAD.MODE.WebDownload", "DOWNLOAD.MODE.MediaWikiDownload", "DOWNLOAD.MODE.OAIDownload", "DOWNLOAD.MODE.ZDownload" , "DOWNLOAD.MODE.SRWDownload"};
78 private String CONTENTS[] = null;
79
80 private boolean download_button_enabled = false;
81 private boolean ready = false;
82
83 private JPanel options_pane;
84 // TODO should use Vector to store all loaded downloads!!
85
86 private DesignTree tree;
87 private HashMap download_map;
88 private ServerInfoDialog server_info;
89 private JScrollPane list_scroll;
90 private DownloadScrollPane getter;
91 private String mode = null;
92 private TreePath previous_path;
93 //private String proxy_url = "";
94 private Properties proxy_urls = new Properties();
95 private Proxy proxyObject = null;
96
97 /** Main System code */
98 public DownloadPane() {
99 super();
100 JScrollPane scrol_tmp;
101 this.setComponentOrientation(Dictionary.getOrientation());
102 // TODO: Download the WDownload and the download panel fixed!!
103 getter = new DownloadScrollPane();
104 getter.start();
105 list_scroll = getter.getDownloadJobList();
106 list_scroll.setComponentOrientation(Dictionary.getOrientation());
107
108 // TODO should use Vector to store all loaded downloads!!
109 String lang = Configuration.getLanguage();
110 download_map = new HashMap();
111
112 // run downloadinfo.pl -describeall, load the downloaders into the download_map,
113 // and get back their list of names, which are of the form "<downloader>Download".
114 // Store these names in the CONTENTS[] array as "DOWNLOAD.MODE.<downloader>Download",
115 // with z3950 as a minor exception: DOWNLOAD.MODE.ZDownload.
116 ArrayList<String> downloaderNamesList = loadDownloadersInfo(lang);
117 int size = downloaderNamesList.size();
118 CONTENTS = new String[size];
119 for(int i = 0; i < size; i++) {
120 String downloadName = downloaderNamesList.get(i); // e.g. "WebDownload"
121 CONTENTS[i] = "DOWNLOAD.MODE."+downloadName.replace("3950", ""); // A special case is Z3950Download,
122 // which has to be stored in CONTENTS array as DOWNLOAD.MODE.ZDownload
123 }
124
125 // Creation
126 tree = new DesignTree();
127 tree.setComponentOrientation(Dictionary.getOrientation());
128 options_pane = new JPanel();
129 options_pane.setComponentOrientation(Dictionary.getOrientation());
130
131 JButton clear_cache_button = new GLIButton(Dictionary.get("Mirroring.ClearCache"), Dictionary.get("Mirroring.ClearCache_Tooltip"));
132 clear_cache_button.setEnabled(true);
133 clear_cache_button.setMnemonic(KeyEvent.VK_C);
134
135 JButton download_button = new GLIButton(Dictionary.get("Mirroring.Download"), Dictionary.get("Mirroring.Download_Tooltip"));
136 download_button.setEnabled(true);
137 download_button.setMnemonic(KeyEvent.VK_D);
138
139 JButton information_button = new GLIButton(Dictionary.get("Download.ServerInformation"), Dictionary.get("Download.ServerInformation_Tooltip"));
140 information_button.setEnabled(true);
141 information_button.setMnemonic(KeyEvent.VK_S);
142
143
144 JButton preferences_button = new GLIButton(Dictionary.get("Mirroring.Preferences"), Dictionary.get("Mirroring.Preferences_Tooltip"));
145 preferences_button.setEnabled(true);
146 preferences_button.setMnemonic(KeyEvent.VK_P);
147
148 // Connect
149 clear_cache_button.addActionListener(new ClearCacheListener());
150 download_button.addActionListener(new DownloadButtonListener());
151 preferences_button.addActionListener(new PreferencesButtonActionListener());
152 information_button.addActionListener(new InformationButtonActionListener());
153 tree.addTreeSelectionListener(new TreeListener());
154
155 // Add to Panel
156 JPanel button_pane = new JPanel();
157 button_pane.setComponentOrientation(Dictionary.getOrientation());
158 button_pane.setLayout(new GridLayout(1,4)); // GridLayout so button pane resizes with window-width
159 button_pane.setBorder(BorderFactory.createEtchedBorder());
160 button_pane.add(clear_cache_button);
161 button_pane.add(download_button);
162 button_pane.add(information_button);
163 button_pane.add(preferences_button);
164
165 JPanel tree_pane = new JPanel();
166 tree_pane.setComponentOrientation(Dictionary.getOrientation());
167 tree_pane.setLayout(new BorderLayout());
168 scrol_tmp = new JScrollPane(tree);
169 scrol_tmp.setComponentOrientation(Dictionary.getOrientation());
170 tree_pane.add(scrol_tmp, BorderLayout.CENTER);
171 tree_pane.setPreferredSize(TREE_SIZE);
172
173
174 Color colour_two = Configuration.getColor("coloring.collection_tree_background", false);
175 options_pane.setBackground(colour_two);
176 options_pane.setBorder(BorderFactory.createEtchedBorder());
177
178
179 JScrollPane options_scroll_pane = new JScrollPane(options_pane);
180 options_scroll_pane.setComponentOrientation(Dictionary.getOrientation());
181 JSplitPane mode_pane = new JSplitPane();
182 mode_pane.setComponentOrientation(Dictionary.getOrientation());
183 mode_pane.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
184 if (Dictionary.getOrientation().isLeftToRight()){
185 mode_pane.add(tree_pane,JSplitPane.LEFT);
186 mode_pane.add(options_scroll_pane,JSplitPane.RIGHT);
187 mode_pane.setDividerLocation(TREE_SIZE.width);
188 }else{
189 mode_pane.add(tree_pane,JSplitPane.RIGHT);
190 mode_pane.add(options_scroll_pane,JSplitPane.LEFT);
191 mode_pane.setDividerLocation(1-TREE_SIZE.width);
192 }
193
194
195 JPanel edit_pane = new JPanel();
196 edit_pane.setComponentOrientation(Dictionary.getOrientation());
197 edit_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(2,0,0,0), BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Download Setting"), BorderFactory.createEmptyBorder(2,2,2,2))));
198 edit_pane.setLayout(new BorderLayout());
199 edit_pane.add(mode_pane,BorderLayout.CENTER);
200 edit_pane.add(button_pane,BorderLayout.PAGE_END);
201
202 // Add to "this"
203 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
204 setLayout(new GridLayout(2,1));
205 add(edit_pane);
206 add(list_scroll);
207
208 //set the mode to the first downloader in the list
209 mode = convertCONTENTStoMode(CONTENTS[0]); // e.g. Web
210 generateOptions(options_pane,(Download)download_map.get(mode));
211 previous_path = tree.getSelectionPath();
212 }
213
214 /** System Utilities */
215 public void modeChanged(int gli_mode) {
216 // do nothing at this stage - should we be renewing download options??
217 }
218
219 private void addHeader(String name, Color color, JPanel target_pane) {
220 JPanel header = new JPanel();
221 header.setComponentOrientation(Dictionary.getOrientation());
222 header.setBackground(color);
223 JPanel inner_pane = new JPanel();
224 inner_pane.setComponentOrientation(Dictionary.getOrientation());
225 inner_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createRaisedBevelBorder()));
226 inner_pane.setBackground(color);
227 JLabel header_label = new JLabel("<html><strong>" + name + "</strong></html>");
228 header_label.setComponentOrientation(Dictionary.getOrientation());
229 header_label.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
230 header_label.setHorizontalAlignment(JLabel.CENTER);
231 header_label.setOpaque(true);
232
233 // Layout
234 inner_pane.setLayout(new BorderLayout());
235 inner_pane.add(header_label, BorderLayout.CENTER);
236
237 header.setLayout(new BorderLayout());
238 header.add(inner_pane, BorderLayout.CENTER);
239 target_pane.add(header);
240 }
241
242 /** Supporting Functions */
243 private ArrayList<String> loadDownloadersInfo(String lang) {
244 Document document = null;
245
246 try {
247 if (Gatherer.isGsdlRemote) {
248 String output = Gatherer.remoteGreenstoneServer.getScriptOptions("downloadinfo.pl", "&describeall");
249 Reader reader = new StringReader(output);
250 document = XMLTools.parseXML(reader);
251 }
252 else {
253 ArrayList args_list = new ArrayList();
254 String args[] = null;
255 if(Configuration.perl_path != null) {
256 args_list.add(Configuration.perl_path);
257 } else if(Utility.isWindows()) {
258 args_list.add("Perl.exe");
259 } else {
260 args_list.add("perl");
261 }
262 args_list.add("-S");
263 args_list.add(LocalGreenstone.getBinScriptDirectoryPath()+"downloadinfo.pl");
264 args_list.add("-describeall");
265 args_list.add("-xml");
266 args_list.add("-language");
267 args_list.add(lang);
268
269 // Create the process.
270 args = (String []) args_list.toArray(new String[0]);
271
272 SafeProcess process = new SafeProcess(args);
273 DebugStream.println("Getting Download Info: "+args_list);
274
275 // run the SafeProcess
276 int exitVal = process.runProcess();
277 if(exitVal != 0) {
278 throw new Exception("*** Error running Download Info process, process exited with: "
279 + exitVal);
280 }
281
282 // get the result and process it.
283 // This time we expect XML to have come out of the process std error stream.
284 String errStreamOutput = process.getStdError();
285 ///System.err.println("*********\nDownload Pane data, got:\n" + errStreamOutput + "\n**********\n");
286 StringReader xmlStrReader = new StringReader(errStreamOutput);
287 document = XMLTools.parseXML(xmlStrReader);
288 xmlStrReader.close();
289
290 }
291
292
293 }
294 catch (Exception error) {
295 System.err.println("Failed when trying to parse downloadinfo.pl -describeall");
296 error.printStackTrace();
297 }
298
299 if(document != null) {
300 return parseXML(document.getDocumentElement());
301 }
302
303 return null;
304 }
305
306 private ArrayList<String> parseXML(Node root) {
307 ArrayList<String> downloaders = null;
308 Element downloadList = (Element)root;
309 int length = -1;
310 if(downloadList.hasAttribute("length")) {
311 length = Integer.parseInt(downloadList.getAttribute("length"));
312 downloaders = new ArrayList<String>(length);
313
314 for (Node node = downloadList.getFirstChild(); node != null; node = node.getNextSibling()) {
315 // goes through each <DownloadInfo> of describeAll
316
317 String download_name = null;
318
319 for(Node infoNode = node.getFirstChild();
320 infoNode != null; infoNode = infoNode.getNextSibling()) {
321
322 String node_name = infoNode.getNodeName();
323 if(node_name.equalsIgnoreCase("Name")) { // <Name>WebDownload</Name>
324 download_name = XMLTools.getValue(infoNode); // e.g. WebDownload
325 }
326
327 // At this top level of <DownloadInfo> elements,
328 // skip all the downloaders that are Abstract, as these are pure superclasses
329 else if(node_name.equalsIgnoreCase("Abstract")) {
330 String isAbstract = XMLTools.getValue(infoNode);
331
332 if(isAbstract.equalsIgnoreCase("no") && download_name != null) {
333 downloaders.add(download_name);
334 Download downloader = parseDownloadInfoXML(node); // parse the <DownloadInfo> node properly
335 // now embedded references to abstract superclasses (embedded <DownloadInfo> nodes)
336 // will be handled
337
338 String shortName = download_name.replace("Download", ""); // e.g. "Web"
339 download_map.put(shortName, downloader);
340 }
341 }
342 }
343 }
344 }
345
346 return downloaders;
347 }
348
349 private Download parseDownloadInfoXML(Node root) {
350
351 Download download = new Download();
352 String node_name = null;
353 for (Node node = root.getFirstChild(); node != null; node = node.getNextSibling()) {
354 node_name = node.getNodeName();
355 if(node_name.equalsIgnoreCase("Name")) {
356 String name = XMLTools.getValue(node);
357 download.setName(name);
358 }
359 else if (node_name.equalsIgnoreCase("Desc")) {
360 download.setDescription(XMLTools.getValue(node));
361 }
362 else if (node_name.equalsIgnoreCase("Abstract")) {
363 download.setIsAbstract(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
364 }
365 else if(node_name.equalsIgnoreCase("Arguments")) {
366 for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
367 node_name = arg.getNodeName();
368 if(node_name.equalsIgnoreCase("Option")) {
369 Argument argument = new Argument((Element)arg);
370 argument.parseXML((Element)arg);
371 argument.setValue(argument.getDefaultValue());
372 download.addArgument(argument);
373 }
374
375 }
376 }
377 else if(node_name.equalsIgnoreCase("DownloadInfo")) {
378 Download super_download = parseDownloadInfoXML(node);
379 download.setSuper(super_download);
380 }
381 }
382
383 if(download.getName() != null) {
384 return download;
385 }
386 return null;
387 }
388
389 /** Update the previous setup */
390 private boolean updateArguments(boolean checkRequired)
391 {
392 boolean cont = true;
393 for(int i = 0; i < options_pane.getComponentCount(); i++) {
394
395 Component component = options_pane.getComponent(i);
396 if(component instanceof ArgumentControl) {
397 cont = cont && ((ArgumentControl)component).updateArgument(checkRequired);
398 }
399 }
400
401 if(cont){return true; }
402
403 return false;
404 }
405
406 /** Generate Controls for Options */
407 /* at some stage we should think about which options should be shown for
408 * different modes. Currently, always show all options (unless hidden)*/
409 private void generateOptions(JPanel options_pane, ArgumentContainer data) {
410 options_pane.removeAll();
411 /** Create the current option panel */
412
413 ArrayList arguments = data.getArguments(true, false);
414 int mode = Configuration.getMode();
415 ArrayList added_arguments = new ArrayList();
416
417 for(int i = 0; i < arguments.size(); i++) {
418 Argument argument = (Argument) arguments.get(i);
419
420 if (argument.isHiddenGLI()) continue;
421 ArgumentControl argument_control = new ArgumentControl(argument,false,null);
422 added_arguments.add(argument_control);
423 }
424
425
426 options_pane.setLayout(new GridLayout(added_arguments.size(),1));
427 for(int i = 0; i < added_arguments.size(); i++) {
428 options_pane.add((ArgumentControl)added_arguments.get(i));
429
430 }
431 }
432
433 /** Behaviour Functions */
434 public void afterDisplay() {
435 ready = true;
436 }
437
438
439 public void gainFocus() {
440 if(!ready) {
441 return;
442 }
443
444 // It is also a good time to determine if the download should be enabled - ie if its allowed to be enabled and a valid URL is present in the field.
445 download_button_enabled = true;
446 //download_button.setEnabled(download_button_enabled);
447 }
448
449
450
451 public void refresh(int refresh_reason, boolean ready)
452 {
453 }
454
455 /** Private classes */
456 /** This tree provides a 'table of contents' for the various components of the design process (collection configuration in more technical terms). */
457 private class DesignTree extends JTree {
458
459 private DesignNode root = null;
460 /** Constructor. Automatically generates all of the nodes, in the order of CONTENTS. */
461 public DesignTree() {
462 super();
463 this.setComponentOrientation(Dictionary.getOrientation());
464 resetModel(Configuration.getMode());
465 expandRow(0);
466 setRootVisible(false);
467 setSelectionRow(0);
468 }
469
470 /** Reset the model used by the design page contents tree. This is necessary to hide the partitions entry when in lower detail modes
471 * @param mode the current detail mode as an int
472 */
473 public void resetModel(int mode) {
474 root = new DesignNode("DOWNLOAD.MODE.Root");
475 // Now add the design categories.
476 for(int i = 0; i < CONTENTS.length; i++) {
477 root.add(new DesignNode(CONTENTS[i]));
478 }
479 this.setModel(new DefaultTreeModel(root));
480 updateUI();
481 }
482 /** Set the current view to the one specified.
483 * @param type the name of the desired view as a String
484 */
485 public void setSelectedView(String type) {
486 type = Dictionary.get(type);
487 for(int i = 0; i < root.getChildCount(); i++) {
488 DesignNode child = (DesignNode) root.getChildAt(i);
489 if(child.toString().equals(type)) {
490 TreePath path = new TreePath(child.getPath());
491 setSelectionPath(path);
492 }
493 }
494 }
495 }
496
497 /** A tree node that retains a reference to one of the possible design sub-views relating to the different sub-managers. */
498 private class DesignNode extends DefaultMutableTreeNode {
499 /** Constructor.
500 * @param object The <strong>Object</strong> assigned to this node.
501 */
502 public DesignNode(String object) {
503 super(object);
504 }
505 /** Retrieve a textual representation of the object.
506 * @return a String
507 */
508 public String toString() {
509 // return Dictionary.get("CDM.GUI." + (String)getUserObject());
510 return Dictionary.get((String) getUserObject());
511 }
512 }
513
514 /** Listens for selection changes in the 'contents' tree, and switches to the appropriate view. */
515 private class TreeListener
516 implements TreeSelectionListener {
517 /** Called whenever the selection changes, we must update the view so it matches the node selected.
518 * @param event A <strong>TreeSelectionEvent</strong> containing more information about the tree selection.
519 * @see org.greenstone.gatherer.cdm.ClassifierManager
520 * @see org.greenstone.gatherer.cdm.CollectionDesignManager
521 * @see org.greenstone.gatherer.cdm.CollectionMetaManager
522 * @see org.greenstone.gatherer.cdm.FormatManager
523 * @see org.greenstone.gatherer.cdm.LanguageManager
524 * @see org.greenstone.gatherer.cdm.MetadataSetView
525 * @see org.greenstone.gatherer.cdm.SubcollectionManager
526 * @see org.greenstone.gatherer.cdm.TranslationView
527 * @see org.greenstone.gatherer.cdm.PlugInManager
528 */
529 public void valueChanged(TreeSelectionEvent event) {
530 if(!tree.isSelectionEmpty()) {
531 TreePath path = tree.getSelectionPath();
532
533 DesignNode node = (DesignNode)path.getLastPathComponent();
534 String type = (String)node.getUserObject();
535 Gatherer.g_man.wait(true);
536
537 // type has the value DOWNLOAD.MODE.<downloader>Download,
538 // mode should then be of the form <downloader>
539 mode = convertCONTENTStoMode(type);
540 generateOptions(options_pane,(Download)download_map.get(mode));
541
542 tree.setSelectionPath(path);
543 previous_path = path;
544 repaint();
545
546 Gatherer.g_man.wait(false);
547 }
548 }
549 }
550
551 private String convertCONTENTStoMode(String content) {
552 return content.replace("DOWNLOAD.MODE.", "").replace("ZDownload", "Z3950").replace("Download", "");
553 }
554
555 private class ClearCacheListener
556 implements ActionListener {
557 public void actionPerformed(ActionEvent event) {
558 // Retrieve the cache folder and delete it.
559 Utility.delete(Utility.getCacheDir());
560 // ...and refresh the node in the workspace tree to show it's all gone
561 Gatherer.g_man.refreshWorkspaceTree(WorkspaceTree.DOWNLOADED_FILES_CHANGED);
562 }
563 }
564
565 private class DownloadButtonListener
566 implements ActionListener {
567 public void actionPerformed(ActionEvent event) {
568
569 if(checkURL(true) && checkProxy() == true) {
570
571 // Proxy settings are now set. Check that the url is not a redirect, else get
572 // redirect url (we do this step in order to avoid some unintuitive behaviour from wget)
573 Download current_download = (Download)download_map.get(mode);
574
575 boolean noCheckCertificate = Configuration.get("general.no_check_certificate", true);
576 Argument no_check_cert_arg = current_download.getArgument("no_check_certificate");
577 if(noCheckCertificate) {
578 no_check_cert_arg.setValue("true");
579 no_check_cert_arg.setAssigned(true);
580 } else {
581 no_check_cert_arg.setValue("false");
582 no_check_cert_arg.setAssigned(false); // only assigned Arguments have values
583 }
584
585 Argument arg_url = current_download.getArgument("url");
586
587 if(arg_url != null) { // it's null for z3950 and possibly for other downloaders
588 String url_str = arg_url.getValue();
589
590 // No longer following URL redirects, since some of this has been taken care of by wget
591 // For the rest, assume the user will get the URL right that they want to download from
592 /*
593 String redirect_url_str = getRedirectURL(url_str);
594
595 // only update the Argument and its GUI ArgumentControl if the URL
596 // has in fact changed
597 if(!url_str.equals(redirect_url_str)) {
598 arg_url.setValue(redirect_url_str);
599 updateArgument(arg_url, redirect_url_str);
600 }
601 */
602 }
603
604 getter.newDownloadJob((Download)download_map.get(mode) ,mode,proxy_url);
605 }
606 }
607 }
608
609 /**
610 * The Java code here will retrieve the page at the given url. If the response code is
611 * a redirect, it will get the redirect url so that wget may be called with the proper url.
612 * This preprocessing of the URL is necessary because:
613 * Wget does not behave the way the browser does when faced with urls of the form
614 * http://www.englishhistory.net/tudor/citizens and if that page does not exist.
615 * The directory listing with a slash at the end (http://www.englishhistory.net/tudor/citizens/)
616 * does exist, however. In order to prevent wget from assuming that the root URL
617 * to traverse is http://www.englishhistory.net/tudor/ instead of the intended
618 * http://www.englishhistory.net/tudor/citizens/, we need give wget the redirect location
619 * that's returned when we initially make a request for http://www.englishhistory.net/tudor/citizens
620 * The proper url is sent back in the Location header, allowing us to bypass wget's
621 * unexpected behaviour.
622 * This method ensures that urls like http://www.nzdl.org/niupepa also continue to work:
623 * there is no http://www.nzdl.org/niupepa/ page, because this url actually redirects to an
624 * entirely different URL.
625 * @return the redirect url for the given url if any redirection is involved, or the
626 * url_str.
627 *
628 * Adding another useful URL on setting Java System Properties:
629 * https://stackoverflow.com/questions/12181843/using-java-to-download-files-from-a-https-url
630 */
631 private String getRedirectURL(String url_str) {
632 boolean noMoreRedirects = false;
633 boolean gotException = false;
634 final int TIMEOUT = 2 * 1000; // ms
635
636 HttpURLConnection connection = null;
637 if(url_str.startsWith("http:") || url_str.startsWith("https:")) { // only test http urls
638 try {
639 // URLConnectionManager class has special handling for https URLs,
640 // so you can control whether you want it to check an HTTPS site's security certificates for you or not
641 boolean noCheckCertificates = true;
642 connection = (HttpURLConnection)URLConnectionManager.getConnection(url_str, this.proxyObject, noCheckCertificates);
643
644 // don't let it automatically follow redirects, since we want to
645 // find out whether we are dealing with redirects in the first place
646 connection.setInstanceFollowRedirects(false);
647 // Connection timeout: if we can't connect, like if the proxy is wrong, don't wait forever
648 // Read timeout: *idle time* when retrieving a link. Don't wait forever to retrieve a page (e.g. if page doesn't exist)
649 // https://stackoverflow.com/questions/6829801/httpurlconnection-setconnecttimeout-has-no-effect
650 connection.setConnectTimeout(TIMEOUT);
651 connection.setReadTimeout(TIMEOUT);
652
653 // now check for whether we get a redirect response
654 // HTTP Codes 3xx are redirects, http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
655 int responseCode = connection.getResponseCode();
656 if(responseCode >= 300 && responseCode < 400) {
657 //String responseMsg = connection.getResponseMessage();
658
659 // Get the Location header since this specifies the new location of the resource
660 String location = connection.getHeaderField("Location");
661
662 // this becomes the url that wget should download from
663 url_str = location.trim();
664 } else {
665 noMoreRedirects = true;
666 }
667 connection.disconnect();
668 } catch(Exception e) {
669 gotException = true;
670 if(connection != null) {
671 connection.disconnect();
672 }
673 System.err.println("Checking redirection. Tried to connect to "
674 + url_str + ",\nbut got exception: " + e);
675 }
676 }
677
678 if(noMoreRedirects || gotException) {
679 return url_str;
680 }
681 else { // continue checking for whether the new URL redirects elsewhere again
682 return getRedirectURL(url_str);
683 }
684 }
685
686
687 /** For a string-based Argument whose value has changed, this method
688 * updates the GUI ArgumentControl's value correspondingly. */
689 private void updateArgument(Argument arg, String value) {
690 for(int i = 0; i < options_pane.getComponentCount(); i++) {
691 Component component = options_pane.getComponent(i);
692 if(component instanceof ArgumentControl) {
693 ArgumentControl control = (ArgumentControl)component;
694 if(control.getArgument() == arg) {
695 control.setValue(value);
696 control.repaint();
697 }
698 }
699 }
700 }
701
702 private boolean checkURL(boolean checkRequired){
703
704 if (!updateArguments(checkRequired)){
705 return false;
706 }
707
708 Download current_download = (Download)download_map.get(mode);
709 Argument arg_url = current_download.getArgument("url");
710
711 if (arg_url == null) return true;
712
713 String url_str = arg_url.getValue();
714 URL url = null;
715 try {
716 url = new URL(url_str);
717 }
718 catch(MalformedURLException error) {
719 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Mirroring.Invalid_URL"), Dictionary.get("Mirroring.Invalid_URL_Title"), JOptionPane.ERROR_MESSAGE);
720 return false;
721 }
722
723 return true;
724 }
725
726
727 // TODO: https://arstechnica.com/civis/viewtopic.php?f=10&t=1281165
728 // "http or https to an https proxy?"
729 // About "CONNECT": https://daniel.haxx.se/docs/sshproxy.html
730 // "You need an SSH client that can issue CONNECT requests through the company HTTP proxy." Seems to imply http? Also uses it for ftp.
731 // https://forum.ivorde.com/set-up-ftp-proxy-via-command-line-in-linux-freebsd-t19733.html sets ftp_proxy to a http url.
732 // So it's seems to be just whatever protocol the proxy server has. When the proxy supports all three protocols
733 // (apparently the common case as per page below describing firefox prefs), then they wiki.archlinux sets the all three ftp_proxy/http_proxy/https_proxy to the same.
734 // See https://forums.freebsd.org/threads/57378/
735 // "I believe that ftp(1) only uses HTTP-type proxies for fetching URLs. I.e. you can't do traditional open->cd->get interactive style of FTP with it via a HTTP proxy. If you do something like ftp ftp://ftp.example.com/path/file, it should work with your proxy setup. For traditional interactive FTP, you need to be directly talking to the remote server or using the less common FTP proxy/gate functionality."
736
737 // https://wiki.archlinux.org/index.php/Proxy_settings
738 // This does https_proxy = http_proxy, and explicitly prefixes "https://" to http_proxy.
739 // https://www.howtogeek.com/293213/how-to-configure-a-proxy-server-in-firefox/
740 /* You’ll usually want to click the “Use the proxy server for all protocols” option. Firefox will also use your HTTP proxy server for SSL-encrypted HTTPS connections and File Transfer Protocol (FTP) connections.
741Uncheck this box if you want to enter separate proxy servers for HTTP, HTTPS, and FTP connections. This isn’t common.
742If you’re configuring a SOCKS proxy, leave the HTTP Proxy, SSL Proxy, and FTP Proxy boxes empty. Enter the address of the SOCKS proxy into the “SOCKS Host” and its port into the “Port” box.
743 */
744 // DONE. TODO: Still need to read up on and test how to set wget proxy on windows
745 // Need to be on a windows machine that requires proxy, and get wget to work on cmdline
746 // If that works, then need to check https URLS also work.
747 // See https://superuser.com/questions/526710/how-to-set-http-proxy-address-for-wget-under-windows
748 private boolean checkProxy(){
749
750 //proxy_url = null;
751 proxy_urls.clear();
752 proxy_urls.setProperty("HTTP", "");
753 proxy_urls.setProperty("HTTPS", "");
754 proxy_urls.setProperty("FTP", "");
755
756 Download current_download = (Download)download_map.get(mode);
757
758 Argument arg = current_download.getArgument("proxy_on");
759
760 if (arg == null) return true;
761
762 // Determine if we have to use a proxy.
763 if(Configuration.get("general.use_proxy", true)) {
764
765 String proxy_host = Configuration.getString("general.proxy_host", true);
766 String proxy_port = Configuration.getString("general.proxy_port", true);
767 // Find out whether the user has already authenticated themselves
768 String user_pass = "";
769 String address = proxy_host + ":" + proxy_port;
770
771 int count = 0;
772 // Only for wget, need to avoid a second automatic authentication popup (first asks
773 // the proxy authentication for wget, and the second will ask the same for the realm)
774 // Once the authentication has been reused, it will set the GAuthenticator state back to REGULAR
775 GAuthenticator.setMode(GAuthenticator.DOWNLOAD);
776 while(count < 3 && (user_pass = (String) GAuthenticator.authentications.get(address)) == null) {
777 Authenticator.requestPasswordAuthentication(proxy_host, null, Integer.parseInt(proxy_port), "http://", Dictionary.get("WGet.Prompt"), "HTTP");
778 count++;
779 }
780 if(count >= 3) {
781 return false;
782 }
783
784 // https://askubuntu.com/questions/664777/systemwide-proxy-settings-in-ubuntu
785 // http://www.rgagnon.com/javadetails/java-0085.html
786 // how-do-i-make-httpurlconnection-use-a-proxy
787 // https://stackoverflow.com/questions/8030908/how-to-check-if-proxy-is-working-in-java
788 proxyObject = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxy_host, Integer.parseInt(proxy_port)));
789
790 if(user_pass.indexOf("@") != -1) {
791
792 arg.setValue("true"); // proxy_on argument
793 arg.setAssigned(true);
794
795 arg = current_download.getArgument("proxy_host");
796 arg.setValue(proxy_host);
797 arg.setAssigned(true);
798
799 arg = current_download.getArgument("proxy_port");
800 arg.setValue(proxy_port);
801 arg.setAssigned(true);
802
803
804 // Write the use proxy command - we don't do this anymore, instead we set environment variables - hopefully these can't be spied on like the following can (using ps) - actually the environment stuff didn't work for windows, so lets go back to this
805 /*if (Utility.isWindows()) {
806
807 arg = current_download.getArgument("user_name");
808 arg.setValue(user_pass.substring(0, user_pass.indexOf("@")));
809 arg.setAssigned(true);
810
811 arg = current_download.getArgument("user_password");
812 arg.setValue(user_pass.substring(user_pass.indexOf("@") + 1));
813 arg.setAssigned(true);
814 }
815
816 else{*/
817 String user_name = user_pass.substring(0, user_pass.indexOf("@"));
818 String user_pwd = user_pass.substring(user_pass.indexOf("@") + 1);
819 proxy_url = user_name+":"+user_pwd+"@"+proxy_host+":"+proxy_port+"/";
820
821 /*}*/
822
823 return true;
824 }
825 else{
826 // unset proxy_on argument
827 arg = current_download.getArgument("proxy_on");
828 arg.setValue("false");
829 arg.setAssigned(false);
830 return false;
831 }
832
833 } else {
834 // unset proxy_on argument
835 arg = current_download.getArgument("proxy_on");
836 arg.setValue("false");
837 arg.setAssigned(false);
838 }
839
840 return true;
841 }
842
843 /*
844 private class PreferencesButtonActionListener
845 implements ActionListener {
846 public void actionPerformed(ActionEvent event) {
847 new Preferences(Preferences.CONNECTION_PREFS);
848 }
849 }*/
850
851 private class InformationButtonActionListener
852 implements ActionListener {
853 public void actionPerformed(ActionEvent event) {
854 //turn off the check for find argument
855 Download current_download = (Download)download_map.get(mode);
856
857 if (!checkProxy() || !checkURL(false) )return;
858
859 if(server_info != null) {
860 server_info.dispose();
861 }
862
863 Argument arg_url = current_download.getArgument("url");
864 String str_url = "";
865 if( arg_url!= null && arg_url.isAssigned()) {
866 str_url = arg_url.getValue();
867 /*
868 String redirected_url = getRedirectURL(str_url); // work out the real URL
869 if(!str_url.equals(redirected_url)) {
870 arg_url.setValue(redirected_url);
871 }
872 */
873 }
874
875 boolean noCheckCertificate = Configuration.get("general.no_check_certificate", true);
876 Argument no_check_cert_arg = current_download.getArgument("no_check_certificate");
877 if(noCheckCertificate) {
878 no_check_cert_arg.setValue("true");
879 no_check_cert_arg.setAssigned(true);
880 } else {
881 no_check_cert_arg.setValue("false");
882 no_check_cert_arg.setAssigned(false); // only assigned Arguments have values
883 }
884
885 server_info = new ServerInfoDialog(str_url ,proxy_url, mode,(Download)download_map.get(mode));
886
887 }
888 }
889
890 private class PreferencesButtonActionListener
891 implements ActionListener {
892 public void actionPerformed(ActionEvent event) {
893 new Preferences(Preferences.CONNECTION_PREFS);
894 }
895 }
896}
Note: See TracBrowser for help on using the repository browser.