1 /*
2  * TorrentDownloaderFactory.java
3  *
4  * Created on 2. November 2003, 03:52
5  * Copyright (C) Azureus Software, Inc, All Rights Reserved.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  */
19 
20 package org.gudy.azureus2.core3.torrentdownloader;
21 
22 import java.io.File;
23 import java.net.URL;
24 import java.util.HashMap;
25 import java.util.Map;
26 
27 import org.gudy.azureus2.core3.global.GlobalManager;
28 import org.gudy.azureus2.core3.torrentdownloader.impl.TorrentDownloaderImpl;
29 import org.gudy.azureus2.core3.torrentdownloader.impl.TorrentDownloaderManager;
30 import org.gudy.azureus2.core3.util.AENetworkClassifier;
31 import org.gudy.azureus2.core3.util.Debug;
32 import org.gudy.azureus2.core3.util.TorrentUtils;
33 import org.gudy.azureus2.core3.util.UrlUtils;
34 
35 import com.aelitis.azureus.core.proxy.AEProxyFactory;
36 import com.aelitis.azureus.core.proxy.AEProxyFactory.PluginProxy;
37 
38 /**
39  *
40  * @author  Tobias Minich
41  */
42 public class TorrentDownloaderFactory {
43 
getClass(boolean logged)44   private static TorrentDownloaderImpl getClass(boolean logged) {
45     try {
46       return (TorrentDownloaderImpl) Class.forName("org.gudy.azureus2.core3.torrentdownloader.impl.TorrentDownloader"+(logged?"Logged":"")+"Impl").newInstance();
47     } catch (Exception e) {
48     	Debug.printStackTrace( e );
49       return null;
50     }
51   }
52 
53   /**
54    * creates and initializes a TorrentDownloader object with the specified parameters.
55    * NOTE: this does not actually start the TorrentDownloader object
56    * @param callback object to notify about torrent download status
57    * @param url url of torrent file to download
58    * @param referrer url of referrer to set as HTTP_REFERER header when requesting torrent
59    * @param fileordir path to a file or directory that the actual
60    *        torrent file should be saved to. if a default save directory is not specified, this will be used instead.
61    * 		even if a default save directory is specified, if this parameter path refers to a file, the filename will
62    * 		be used when saving the torrent
63    * @param whether or not logging is enabled for the torrent download. this is performed through the TorrentDownloaderLoggedImpl class which is only available in the uis project
64    * @return
65    */
66   public static TorrentDownloader
create( TorrentDownloaderCallBackInterface callback, String url, String referrer, String fileordir, boolean logged )67   create(
68   	TorrentDownloaderCallBackInterface 	callback,
69 	String 								url,
70 	String								referrer,
71 	String 								fileordir,
72 	boolean 							logged )
73   {
74 	  return( create( callback, url, referrer, null, fileordir, logged ));
75   }
76 
77   public static TorrentDownloader
create( TorrentDownloaderCallBackInterface callback, String url, String referrer, String fileordir )78   create(
79   		TorrentDownloaderCallBackInterface 	callback,
80 		String 								url,
81 		String								referrer,
82 		String 								fileordir )
83   {
84     return create(callback, url, referrer, fileordir, false );
85   }
86 
87   public static TorrentDownloader
create( TorrentDownloaderCallBackInterface callback, String url, String referrer, Map request_properties, String fileordir)88   create(
89   		TorrentDownloaderCallBackInterface 	callback,
90 		String 								url,
91 		String								referrer,
92 		Map									request_properties,
93 		String 								fileordir)
94   {
95 	  return( create( callback, url, referrer, request_properties, fileordir, false ));
96   }
97 
98   private static TorrentDownloader
create( TorrentDownloaderCallBackInterface callback, String url, String referrer, Map request_properties, String fileordir, boolean logged )99   create(
100   		TorrentDownloaderCallBackInterface 	callback,
101 		String 								url,
102 		String								referrer,
103 		Map									request_properties,
104 		String 								fileordir,
105 		boolean								logged )
106   {
107 	  return( new TorrentDownloadRetrier( callback, url, referrer, request_properties, fileordir, logged ));
108   }
109 
create(TorrentDownloaderCallBackInterface callback, String url, boolean logged)110   public static TorrentDownloader create(TorrentDownloaderCallBackInterface callback, String url, boolean logged) {
111     return create(callback, url, null, null, logged);
112   }
113 
create(TorrentDownloaderCallBackInterface callback, String url)114   public static TorrentDownloader create(TorrentDownloaderCallBackInterface callback, String url) {
115       return create(callback, url, null, null, false);
116   }
117 
create(String url, String fileordir, boolean logged)118   public static TorrentDownloader create(String url, String fileordir, boolean logged) {
119     return create(null, url, null, fileordir, logged);
120   }
121 
create(String url, String fileordir)122   public static TorrentDownloader create(String url, String fileordir) {
123     return create(null, url, null, fileordir, false);
124   }
125 
create(String url, boolean logged)126   public static TorrentDownloader create(String url, boolean logged) {
127     return create(null, url, null, null, logged);
128   }
129 
create(String url)130   public static TorrentDownloader create(String url) {
131     return create(null, url, null, null, false);
132   }
133 
initManager(GlobalManager gm, boolean logged, boolean autostart, String downloaddir)134   public static void initManager(GlobalManager gm, boolean logged, boolean autostart, String downloaddir) {
135     TorrentDownloaderManager.getInstance().init(gm, logged, autostart, downloaddir);
136   }
137 
downloadManaged(String url, String fileordir, boolean logged)138   public static TorrentDownloader downloadManaged(String url, String fileordir, boolean logged) {
139     return TorrentDownloaderManager.getInstance().download(url, fileordir, logged);
140   }
141 
downloadManaged(String url, String fileordir)142   public static TorrentDownloader downloadManaged(String url, String fileordir) {
143     return TorrentDownloaderManager.getInstance().download(url, fileordir);
144   }
145 
downloadManaged(String url, boolean logged)146   public static TorrentDownloader downloadManaged(String url, boolean logged) {
147     return TorrentDownloaderManager.getInstance().download(url, logged);
148   }
149 
downloadManaged(String url)150   public static TorrentDownloader downloadManaged(String url) {
151     return TorrentDownloaderManager.getInstance().download(url);
152   }
153 
154   	private static class
155   	TorrentDownloadRetrier
156   		implements TorrentDownloader
157   	{
158 		final private String 								url;
159 		final private String								referrer;
160 		final private Map									request_properties;
161 		final private String 								fileordir;
162 		final private boolean								logged;
163 
164 		private volatile TorrentDownloaderImpl	delegate;
165 
166 		private volatile boolean	cancelled;
167 
168 		private volatile boolean	sdp_set;
169 		private volatile String		sdp_path;
170 		private volatile String		sdp_file;
171 
172 		private volatile boolean	dfoc_set;
173 		private volatile boolean	dfoc;
174 		private volatile boolean	irc_set;
175 		private volatile boolean	irc;
176 
177 		private volatile String		original_error;
178 
179   		private
TorrentDownloadRetrier( final TorrentDownloaderCallBackInterface _callback, String _url, String _referrer, Map _request_properties, String _fileordir, boolean _logged )180   		TorrentDownloadRetrier(
181   			final TorrentDownloaderCallBackInterface 	_callback,
182   			String 										_url,
183   			String										_referrer,
184   			Map											_request_properties,
185   			String 										_fileordir,
186   			boolean										_logged )
187   		{
188   			url					= _url;
189   			referrer			= _referrer;
190   			request_properties	= _request_properties;
191   			fileordir			= _fileordir;
192   			logged				= _logged;
193 
194   			TorrentDownloaderCallBackInterface callback			=
195   				new TorrentDownloaderCallBackInterface()
196   				{
197   					private TorrentDownloaderCallBackInterface	original_callback = _callback;
198 
199   					private boolean no_retry = original_callback == null;
200 
201   					private boolean	init_reported 		= false;
202   					private boolean	start_reported		= false;
203   					private boolean	finish_reported		= false;
204 
205   					private boolean			proxy_tried = false;
206   					private PluginProxy		plugin_proxy;
207 
208   					public void
209   					TorrentDownloaderEvent(
210   						int 				state,
211   						TorrentDownloader 	_delegate )
212   					{
213   						if ( _delegate != delegate ){
214 
215   							return;
216   						}
217 
218   						if ( state == STATE_ERROR ){
219 
220   							if ( original_error == null ){
221 
222   								original_error = delegate.getError();
223   							}
224   						}
225 
226   						if (	plugin_proxy != null &&
227   								(	state == STATE_FINISHED ||
228   									state == STATE_DUPLICATE ||
229   									state == STATE_CANCELLED ||
230   									state == STATE_ERROR )){
231 
232   							plugin_proxy.setOK( state != STATE_ERROR );
233 
234   							plugin_proxy = null;
235   						}
236 
237 
238   						synchronized( this ){
239 
240 	  						if ( state == STATE_INIT ){
241 
242 	  							if ( init_reported ){
243 
244 	  								return;
245 	  							}
246 
247 	  							init_reported = true;
248 	  						}
249 
250 	 						if ( state == STATE_START ){
251 
252 	  							if ( start_reported ){
253 
254 	  								return;
255 	  							}
256 
257 	  							start_reported = true;
258 	  						}
259 
260 	 						if ( state == STATE_FINISHED ){
261 
262 	  							if ( finish_reported ){
263 
264 	  								return;
265 	  							}
266 
267 	  							finish_reported = true;
268 	  						}
269   						}
270 
271   						if ( cancelled ){
272 
273   							no_retry = true;
274   						}
275 
276   						if ( no_retry ){
277 
278   							if ( original_callback != null ){
279 
280   								original_callback.TorrentDownloaderEvent( state, TorrentDownloadRetrier.this );
281   							}
282 
283   							return;
284   						}
285 
286   						if ( 	state == STATE_FINISHED ||
287   								state == STATE_DUPLICATE ||
288   								state == STATE_CANCELLED ){
289 
290   							if ( state == STATE_FINISHED  && proxy_tried ){
291 
292   								TorrentUtils.setObtainedFrom( delegate.getFile(), url );
293   							}
294 
295 							if ( original_callback != null ){
296 
297   								original_callback.TorrentDownloaderEvent( state, TorrentDownloadRetrier.this );
298   							}
299 
300   							no_retry = true;
301 
302   							return;
303   						}
304 
305   						if ( state == STATE_ERROR ){
306 
307  							String lc_url = url.toLowerCase().trim();
308 
309   							if ( !proxy_tried ){
310 
311   								proxy_tried = true;
312 
313   								boolean	tor_hack = lc_url.startsWith( "tor:" );
314 
315   	  							if ( lc_url.startsWith( "http" ) || tor_hack ){
316 
317   	  								try{
318   	  									URL original_url;
319 
320   	  									if ( tor_hack ){
321 
322   	  										original_url = new URL( url.substring( 4 ));
323 
324   	  										Map<String,Object>	options = new HashMap<String,Object>();
325 
326   	  										options.put( AEProxyFactory.PO_PEER_NETWORKS, new String[]{ AENetworkClassifier.AT_TOR });
327 
328 		  	  								plugin_proxy =
329 		  	  									AEProxyFactory.getPluginProxy(
330 		  	  										"torrent download",
331 		  	  										original_url,
332 		  	  										options,
333 		  	  										true );
334 		  	  							}else{
335 
336 		  	  								original_url = new URL( url );
337 		  	  							}
338 
339   	  									plugin_proxy = AEProxyFactory.getPluginProxy( "torrent download", original_url );
340 
341   	  									if ( plugin_proxy != null ){
342 
343 	  	  									delegate = TorrentDownloaderFactory.getClass( logged );
344 
345 	  	  									if ( sdp_set ){
346 
347 	  	  										delegate.setDownloadPath( sdp_path, sdp_file );
348 	  	  									}
349 
350 		  	  	  				 			if ( dfoc_set ){
351 
352 		  	  	  				 				delegate.setDeleteFileOnCancel( dfoc );
353 		  	  	  				 			}
354 
355 		  	  	  				 			if ( irc_set ){
356 
357 		  	  	  				 				delegate.setIgnoreReponseCode( irc );
358 		  	  	  				 			}
359 
360 		  	  	  				 			Map props = new HashMap();
361 
362 		  	  	  				 			if ( request_properties != null ){
363 
364 		  	  	  				 				props.putAll( request_properties );
365 		  	  	  				 			}
366 
367 		  	  	  				 			props.put( "HOST", plugin_proxy.getURLHostRewrite() + (original_url.getPort()==-1?"":(":"+original_url.getPort())));
368 
369 		  	  	  				  			delegate.init( this, plugin_proxy.getURL().toExternalForm(), plugin_proxy.getProxy(), referrer, props, fileordir );
370 
371 		  	  	  							delegate.start();
372 
373 		  	  	  							return;
374   	  									}
375   	  								}catch( Throwable e ){
376 
377   	  								}
378   	  							}
379   							}
380 
381   							String	retry_url = null;
382 
383   							if ( lc_url.startsWith( "http" )){
384 
385   								retry_url = UrlUtils.parseTextForURL( url.substring( 5 ), true );
386   							}
387 
388   							if ( retry_url != null ){
389 
390 	  				 			delegate = TorrentDownloaderFactory.getClass( logged );
391 
392 	  				 			if ( sdp_set ){
393 
394 	  				 				delegate.setDownloadPath( sdp_path, sdp_file );
395 	  				 			}
396 
397 	  				 			if ( dfoc_set ){
398 
399 	  				 				delegate.setDeleteFileOnCancel( dfoc );
400 	  				 			}
401 
402 	  				 			if ( irc_set ){
403 
404 	  				 				delegate.setIgnoreReponseCode( irc );
405 	  				 			}
406 
407 	  				  			delegate.init( this, retry_url, null, referrer, request_properties, fileordir );
408 
409 	  							no_retry	= true;
410 
411 	  							delegate.start();
412 
413 	  							return;
414 
415   							}else{
416 
417 	  							no_retry	= true;
418   							}
419   						}
420 
421 						if ( original_callback != null ){
422 
423 							original_callback.TorrentDownloaderEvent( state, TorrentDownloadRetrier.this );
424 						}
425   					}
426 
427   				};
428 
429   			delegate = TorrentDownloaderFactory.getClass( logged );
430 
431   			delegate.init( callback, url, null, referrer, request_properties, fileordir );
432   		}
433 
434   		public void
start()435   		start()
436   		{
437   			delegate.start();
438   		}
439 
440   		public void
cancel()441   		cancel()
442   		{
443   			cancelled = true;
444 
445   			delegate.cancel();
446   		}
447 
448   		public void
setDownloadPath( String path, String file)449   		setDownloadPath(
450   			String path,
451   			String file)
452   		{
453   			sdp_set			= true;
454  			sdp_path		= path;
455   			sdp_file		= file;
456 
457   			delegate.setDownloadPath(path, file);
458    		}
459 
460   		public int
getDownloadState()461   		getDownloadState()
462   		{
463   			return( delegate.getDownloadState());
464   		}
465 
466   		public File
getFile()467   		getFile()
468   		{
469   			return( delegate.getFile());
470   		}
471 
472   		public int
getPercentDone()473   		getPercentDone()
474   		{
475   			return( delegate.getPercentDone());
476   		}
477 
478   		public int
getTotalRead()479   		getTotalRead()
480   		{
481   			return( delegate.getTotalRead());
482   		}
483 
484   		public String
getError()485   		getError()
486   		{
487   			if ( original_error != null ){
488 
489   				return( original_error );
490   			}
491 
492   			return( delegate.getError());
493   		}
494 
495   		public String
getStatus()496   		getStatus()
497   		{
498   			return( delegate.getStatus());
499   		}
500 
501   		public String
getURL()502   		getURL()
503   		{
504   			return( delegate.getURL());
505   		}
506 
507   		public int
getLastReadCount()508   		getLastReadCount()
509   		{
510   			return( delegate.getLastReadCount());
511   		}
512 
513   		public byte[]
getLastReadBytes()514   		getLastReadBytes()
515   		{
516   			return( delegate.getLastReadBytes());
517   		}
518 
519   		public boolean
getDeleteFileOnCancel()520   		getDeleteFileOnCancel()
521   		{
522   			return( delegate.getDeleteFileOnCancel());
523   		}
524 
525   		public void
setDeleteFileOnCancel( boolean deleteFileOnCancel )526   		setDeleteFileOnCancel(
527   			boolean deleteFileOnCancel )
528   		{
529   			dfoc_set	= true;
530   			dfoc		= deleteFileOnCancel;
531 
532   			delegate.setDeleteFileOnCancel( deleteFileOnCancel );
533   		}
534 
535   		public boolean
isIgnoreReponseCode()536   		isIgnoreReponseCode()
537   		{
538   			return( delegate.isIgnoreReponseCode());
539   		}
540 
541   		public void
setIgnoreReponseCode( boolean ignoreReponseCode)542   		setIgnoreReponseCode(
543   			boolean ignoreReponseCode)
544   		{
545   			irc_set	= true;
546   			irc		= ignoreReponseCode;
547 
548   			delegate.setIgnoreReponseCode( ignoreReponseCode );
549   		}
550   	}
551 }
552