/* * Created on 8 juil. 2003 * Copyright (C) 2003, 2004, 2005, 2006 Aelitis, All Rights Reserved. * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * AELITIS, SAS au capital de 46,603.30 euros * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. * */ package org.gudy.azureus2.ui.swt; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.gudy.azureus2.core3.config.COConfigurationManager; import org.gudy.azureus2.core3.logging.LogAlert; import org.gudy.azureus2.core3.logging.LogEvent; import org.gudy.azureus2.core3.logging.LogIDs; import org.gudy.azureus2.core3.logging.Logger; import org.gudy.azureus2.core3.util.AEMonitor; import org.gudy.azureus2.core3.util.AEThread; import org.gudy.azureus2.core3.util.Base32; import org.gudy.azureus2.core3.util.ByteFormatter; import org.gudy.azureus2.core3.util.Constants; import org.gudy.azureus2.core3.util.Debug; import org.gudy.azureus2.ui.swt.mainwindow.TorrentOpener; import org.gudy.azureus2.ui.swt.sharing.ShareUtils; import com.aelitis.azureus.core.AzureusCore; import com.aelitis.azureus.core.AzureusCoreComponent; import com.aelitis.azureus.core.AzureusCoreLifecycleAdapter; import com.aelitis.azureus.core.impl.AzureusCoreSingleInstanceClient; import com.aelitis.azureus.ui.UIFunctions; import com.aelitis.azureus.ui.UIFunctionsManager; import com.aelitis.azureus.ui.swt.UIFunctionsSWT; /** * @author Olivier * */ public class StartServer { private static final LogIDs LOGID = LogIDs.GUI; private ServerSocket socket; private int state; private boolean bContinue; public static final int STATE_FAULTY = 0; public static final int STATE_LISTENING = 1; protected List queued_torrents = new ArrayList(); protected boolean core_started = false; protected AEMonitor this_mon = new AEMonitor( "StartServer" ); private static final int START_SERVER_PORT = System.getProperty("oneswarm.integration.start.server.port") == null ? 6885 : Integer.parseInt(System.getProperty("oneswarm.integration.start.server.port")); public StartServer() { try { // NOLAR: only bind to localhost socket = new ServerSocket(START_SERVER_PORT, 50, InetAddress.getByName("127.0.0.1")); state = STATE_LISTENING; if (Logger.isEnabled()) Logger.log(new LogEvent(LOGID, "StartServer: listening on " + "127.0.0.1:" + START_SERVER_PORT + " for passed torrent info")); } catch (Throwable t) { // DON'T USE LOGGER here as we DON't want to initialise all the // logger stuff // and in particular AEDiagnostics config dirty stuff!!!! state = STATE_FAULTY; String reason = t.getMessage() == null ? "<>" : t.getMessage(); System.out.println("StartServer ERROR: unable" + " to bind to 127.0.0.1:" + START_SERVER_PORT + " listening" + " for passed torrent info: " + reason); } } public void pollForConnections(final AzureusCore azureus_core) { azureus_core.addLifecycleListener(new AzureusCoreLifecycleAdapter() { @Override public void componentCreated(AzureusCore core, AzureusCoreComponent component) { if (component instanceof UIFunctionsSWT) { openQueuedTorrents(azureus_core); } } }); if (socket != null) { Thread t = new AEThread("Start Server") { @Override public void runSupport() { pollForConnectionsSupport(azureus_core); } }; t.setDaemon(true); t.start(); } } private void pollForConnectionsSupport( AzureusCore azureus_core ) { bContinue = true; while (bContinue) { BufferedReader br = null; try { Socket sck = socket.accept(); String address = sck.getInetAddress().getHostAddress(); if (address.equals("localhost") || address.equals("127.0.0.1")) { System.out.println("startserver got connection"); br = new BufferedReader(new InputStreamReader(sck.getInputStream(),Constants.DEFAULT_ENCODING)); String line = br.readLine(); System.out.println("received : " + line); if (Logger.isEnabled()) Logger.log(new LogEvent(LOGID, "Main::startServer: received '" + line + "'")); if (line != null) { String [] args = parseArgs(line); if (args != null && args.length > 0) { String debug_str = args[0]; for (int i=1; i<args.length; i++) { debug_str += " ; " + args[i]; } Logger.log(new LogEvent(LOGID, "Main::startServer: decoded to '" + debug_str + "'")); processArgs(azureus_core,args); } } } sck.close(); } catch (Exception e) { if(!(e instanceof SocketException)) Debug.printStackTrace( e ); //bContinue = false; } finally { try { if (br != null) br.close(); } catch (Exception e) { /*ignore */ } } } } private static String[] parseArgs(String line) { if (!line.startsWith(AzureusCoreSingleInstanceClient.ACCESS_STRING + ";")) {return null;} // I'm sure there's a lovely regex which could do this, but I can't be bothered to figure // it out. ArrayList parts = new ArrayList(); StringBuffer buf = new StringBuffer(); boolean escape_mode = false; char c; for (int i=AzureusCoreSingleInstanceClient.ACCESS_STRING.length() + 1; i<line.length(); i++) { c = line.charAt(i); if (escape_mode) {buf.append(c); escape_mode = false;} else if (c == '&') {escape_mode = true;} else if (c == ';') {parts.add(buf.toString()); buf.setLength(0);} else {buf.append(c);} } if (buf.length() > 0) {parts.add(buf.toString());} return (String[])parts.toArray(new String[parts.size()]); } protected void processArgs( AzureusCore azureus_core, String args[]) { for( String s : args ) { System.out.println("processArgs: " + s); } if (args.length < 1 || !args[0].equals( "args" )){ return; } if (args.length == 1 || !COConfigurationManager.getBooleanParameter("add_torrents_silently")) { showMainWindow(); } boolean open = true; for (int i = 1; i < args.length; i++) { String arg = args[i]; if ( i == 1 ){ if ( arg.equalsIgnoreCase( "--closedown" )){ UIFunctions uiFunctions = UIFunctionsManager.getUIFunctions(); if (uiFunctions != null) { uiFunctions.requestShutdown(); } return; }else if ( arg.equalsIgnoreCase( "--open" )){ continue; }else if ( arg.equalsIgnoreCase( "--share" )){ open = false; continue; } } String file_name = arg; File file = new File(file_name); if ( !file.exists() && !isURI( file_name )){ // handle hex info hashes if ( file_name.length() == 40 ){ byte[] hash = null; try{ hash = ByteFormatter.decodeString( file_name ); }catch( Throwable e ){ } if ( hash != null && hash.length == 20 ){ file_name = "magnet:?xt=urn:btih:" + Base32.encode( hash ); } } // handle base32 info hash if ( file_name.length() == 32 ){ byte[] hash = null; try{ hash = Base32.decode( file_name ); }catch( Throwable e ){ } if ( hash != null && hash.length == 20 ){ file_name = "magnet:?xt=urn:btih:" +file_name; } } } if ( isURI( file_name )) { if (Logger.isEnabled()) Logger.log(new LogEvent(LOGID, "StartServer: args[" + i + "] handling as a URI: " + file_name)); }else{ try { if (!file.exists()) { throw (new Exception("File not found")); } file_name = file.getCanonicalPath(); Logger.log(new LogEvent(LOGID, "StartServer: file = " + file_name)); } catch (Throwable e) { Logger.log(new LogAlert(LogAlert.REPEATABLE, LogAlert.AT_ERROR, "Failed to access torrent file '" + file_name + "'. Ensure sufficient temporary file space " + "available (check browser cache usage).")); } } boolean queued = false; try { this_mon.enter(); if (!core_started) { queued_torrents.add( new Object[]{ file_name, new Boolean( open )}); queued = true; } } finally { this_mon.exit(); } if ( !queued ){ handleFile( azureus_core, file_name, open ); } } } protected boolean isURI( String file_name ) { String file_name_lower = file_name.toLowerCase(); return( file_name_lower.startsWith( "http:" ) || file_name_lower.startsWith( "https:" ) || file_name_lower.startsWith( "magnet:" ) || file_name_lower.startsWith("oneswarm:")); } protected void handleFile( AzureusCore azureus_core, String file_name, boolean open ) { try { if ( open ){ TorrentOpener.openTorrent(file_name); }else{ File f = new File( file_name ); if ( f.isDirectory()){ ShareUtils.shareDir( azureus_core, file_name ); }else{ ShareUtils.shareFile( azureus_core, file_name ); } } } catch (Throwable e) { Debug.printStackTrace(e); } } protected void openQueuedTorrents( AzureusCore azureus_core ) { try{ this_mon.enter(); core_started = true; }finally{ this_mon.exit(); } for (int i=0;i<queued_torrents.size();i++){ Object[] entry = (Object[])queued_torrents.get(i); String file_name = (String)entry[0]; boolean open = ((Boolean)entry[1]).booleanValue(); handleFile( azureus_core, file_name, open ); } } protected void showMainWindow() { UIFunctions uiFunctions = UIFunctionsManager.getUIFunctions(); if (uiFunctions != null) { uiFunctions.bringToFront(); } } public void stopIt() { bContinue = false; try { socket.close(); } catch (Throwable e) {/*ignore */} } /** * @return */ public int getState() { return state; } // Test argument parsing code. public static void main(String [] args) { String[] input_tests = new String[] { "a;b;c", "test", AzureusCoreSingleInstanceClient.ACCESS_STRING + ";b;c;d", // Simple test AzureusCoreSingleInstanceClient.ACCESS_STRING + ";b;c&;d;e", // Less simple test AzureusCoreSingleInstanceClient.ACCESS_STRING + ";b;c&&;d;e", // Even less simple test AzureusCoreSingleInstanceClient.ACCESS_STRING + ";b;c&&&;d;e", // Awkward test }; String[][] output_results = new String[][] { null, null, new String[] {"b", "c", "d"}, new String[] {"b", "c;d", "e"}, new String[] {"b", "c&", "d", "e"}, new String[] {"b", "c&;d", "e"}, }; for (int i=0; i<input_tests.length; i++) { System.out.println("Testing: " + input_tests[i]); String[] result = parseArgs(input_tests[i]); if (result == output_results[i]) {continue;} if (Arrays.equals(result, output_results[i])) {continue;} System.out.println("TEST FAILED"); System.out.println(" Expected: " + Arrays.asList(output_results[i])); System.out.println(" Decoded : " + Arrays.asList(result)); System.exit(1); } System.out.println("Done."); } }