/** * Created : May 26, 2012 * * @author pquiring */ import java.io.*; import java.net.*; import java.util.*; import javax.net.ssl.*; import javax.swing.*; import javax.swing.table.*; import javax.swing.filechooser.*; import javaforce.*; import javaforce.linux.*; public class MainPanel extends javax.swing.JPanel { /** * Creates new form MainPanel */ public MainPanel() { initComponents(); This = this; tableModel = (DefaultTableModel)table.getModel(); new File(JF.getUserPath() + "/Torrents").mkdirs(); // JFLog.init(JF.getUserPath() + "/.jftorrent.log", true); loadConfig(); updateList(); startServer(); startTorrents(); initHttps(); java.util.Timer timer = new java.util.Timer(); timer.schedule(new TimerTask() { public void run() { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { updateGUI(); } }); } }, 5000, 5000); } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { jToolBar1 = new javax.swing.JToolBar(); addFile = new javax.swing.JButton(); addURL = new javax.swing.JButton(); jSeparator1 = new javax.swing.JToolBar.Separator(); delete = new javax.swing.JButton(); jSeparator2 = new javax.swing.JToolBar.Separator(); start = new javax.swing.JButton(); pause = new javax.swing.JButton(); stop = new javax.swing.JButton(); jSeparator3 = new javax.swing.JToolBar.Separator(); editConfig = new javax.swing.JButton(); jSeparator5 = new javax.swing.JToolBar.Separator(); status = new javax.swing.JLabel(); jSplitPane2 = new javax.swing.JSplitPane(); jScrollPane1 = new javax.swing.JScrollPane(); list = new javax.swing.JList(); jScrollPane2 = new javax.swing.JScrollPane(); table = new javax.swing.JTable(); jToolBar1.setFloatable(false); jToolBar1.setRollover(true); addFile.setText("Add File"); addFile.setFocusable(false); addFile.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); addFile.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); addFile.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { addFileActionPerformed(evt); } }); jToolBar1.add(addFile); addURL.setText("Add URL"); addURL.setFocusable(false); addURL.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); addURL.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); addURL.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { addURLActionPerformed(evt); } }); jToolBar1.add(addURL); jToolBar1.add(jSeparator1); delete.setText("Delete"); delete.setFocusable(false); delete.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); delete.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); delete.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { deleteActionPerformed(evt); } }); jToolBar1.add(delete); jToolBar1.add(jSeparator2); start.setText("Start"); start.setFocusable(false); start.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); start.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); start.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { startActionPerformed(evt); } }); jToolBar1.add(start); pause.setText("Pause"); pause.setFocusable(false); pause.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); pause.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); pause.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { pauseActionPerformed(evt); } }); jToolBar1.add(pause); stop.setText("Stop"); stop.setFocusable(false); stop.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); stop.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); stop.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { stopActionPerformed(evt); } }); jToolBar1.add(stop); jToolBar1.add(jSeparator3); editConfig.setText("Config"); editConfig.setFocusable(false); editConfig.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); editConfig.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); editConfig.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { editConfigActionPerformed(evt); } }); jToolBar1.add(editConfig); jToolBar1.add(jSeparator5); status.setText("Status:?"); jToolBar1.add(status); jSplitPane2.setDividerLocation(150); jSplitPane2.setResizeWeight(0.1); list.setModel(listModel); list.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); list.addListSelectionListener(new javax.swing.event.ListSelectionListener() { public void valueChanged(javax.swing.event.ListSelectionEvent evt) { listValueChanged(evt); } }); jScrollPane1.setViewportView(list); jSplitPane2.setLeftComponent(jScrollPane1); table.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { }, new String [] { "Name", "#", "Size", "Done", "Status", "Seeds", "Peers", "Down Speed", "Up Speed", "ETA", "Uploaded", "Ratio", "Available" } ) { Class[] types = new Class [] { java.lang.String.class, java.lang.Integer.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class }; boolean[] canEdit = new boolean [] { false, false, false, false, false, false, false, false, false, false, false, false, false }; public Class getColumnClass(int columnIndex) { return types [columnIndex]; } public boolean isCellEditable(int rowIndex, int columnIndex) { return canEdit [columnIndex]; } }); jScrollPane2.setViewportView(table); jSplitPane2.setRightComponent(jScrollPane2); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 609, Short.MAX_VALUE) .addComponent(jSplitPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jSplitPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 519, Short.MAX_VALUE)) ); }// </editor-fold>//GEN-END:initComponents private void addFileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addFileActionPerformed addFile(); updateList(); }//GEN-LAST:event_addFileActionPerformed private void editConfigActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editConfigActionPerformed int orgPort = TorrentServer.port; ConfigDialog dialog = new ConfigDialog(null, true); dialog.setVisible(true); if (!dialog.accepted) return; if (config.port == orgPort) return; saveConfig(); server.changePort(config.port); status.setText("?"); for(int a=0;a<clients.size();a++) { clients.get(a).recontactTracker(); } }//GEN-LAST:event_editConfigActionPerformed private void addURLActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addURLActionPerformed addURL(); updateList(); }//GEN-LAST:event_addURLActionPerformed private void listValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_listValueChanged updateTable(); }//GEN-LAST:event_listValueChanged private void deleteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteActionPerformed int row = table.getSelectedRow(); if (row == -1) return; int idx = (Integer)table.getValueAt(row, 1); TorrentClient client = clients.get(idx); client.close(); clients.remove(client); removeTorrent(idx); updateTable(); updateList(); }//GEN-LAST:event_deleteActionPerformed private void startActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startActionPerformed int row = table.getSelectedRow(); if (row == -1) return; int idx = (Integer)table.getValueAt(row, 1); TorrentClient client = clients.get(idx); client._start(); config.torrent[idx].active = true; config.torrent[idx].paused = false; saveConfig(); }//GEN-LAST:event_startActionPerformed private void pauseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pauseActionPerformed int row = table.getSelectedRow(); if (row == -1) return; int idx = (Integer)table.getValueAt(row, 1); TorrentClient client = clients.get(idx); client.pause(); config.torrent[idx].paused = true; saveConfig(); }//GEN-LAST:event_pauseActionPerformed private void stopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopActionPerformed int row = table.getSelectedRow(); if (row == -1) return; int idx = (Integer)table.getValueAt(row, 1); TorrentClient client = clients.get(idx); client._stop(); config.torrent[idx].active = false; saveConfig(); }//GEN-LAST:event_stopActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton addFile; private javax.swing.JButton addURL; private javax.swing.JButton delete; private javax.swing.JButton editConfig; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JToolBar.Separator jSeparator1; private javax.swing.JToolBar.Separator jSeparator2; private javax.swing.JToolBar.Separator jSeparator3; private javax.swing.JToolBar.Separator jSeparator5; private javax.swing.JSplitPane jSplitPane2; private javax.swing.JToolBar jToolBar1; private javax.swing.JList list; private javax.swing.JButton pause; private javax.swing.JButton start; private javax.swing.JLabel status; private javax.swing.JButton stop; private javax.swing.JTable table; // End of variables declaration//GEN-END:variables private ArrayList<TorrentClient> clients = new ArrayList<TorrentClient>(); public static Config config; private String configFolder = JF.getUserPath(); private String configFile = "/.jftorrent.xml"; private TorrentServer server; private DefaultListModel listModel = new DefaultListModel(); private DefaultTableModel tableModel; public static MainPanel This; public static class Torrent { public String file; public String dest; public boolean active = true, paused = false; } public static class Config { public Torrent torrent[]; public int port; } private void loadConfig() { defaultConfig(); try { XML xml = new XML(); FileInputStream fis = new FileInputStream(configFolder + configFile); xml.read(fis); xml.writeClass(config); } catch (FileNotFoundException e1) { defaultConfig(); } catch (Exception e2) { JFLog.log(e2); defaultConfig(); } } private void defaultConfig() { config = new Config(); config.torrent = new Torrent[0]; config.port = 6881; } private void saveConfig() { try { XML xml = new XML(); FileOutputStream fos = new FileOutputStream(configFolder + configFile); xml.readClass("jftorrent", config); xml.write(fos); fos.close(); } catch (Exception e) { JFLog.log(e); } } private void startServer() { server = new TorrentServer(config.port); server.start(); } private void startTorrents() { for(int a=0;a<config.torrent.length;a++) { startTorrent(config.torrent[a].file, config.torrent[a].dest, config.torrent[a].active, config.torrent[a].paused); } } private boolean startTorrent(String file, String dest, boolean active, boolean paused) { int size = clients.size(); for(int a=0;a<size;a++) { if (clients.get(a).torrent.equals(file)) return false; } TorrentClient client = new TorrentClient(file, dest, active, paused); client.start(); clients.add(client); updateList(); updateTable(); return true; } public void updateList() { int idx = list.getSelectedIndex(); listModel.removeAllElements(); int downloading = 0; int seeding = 0; // int active = 0; // int inactive = 0; int size = clients.size(); for(int a=0;a<size;a++) { TorrentClient client = clients.get(a); if (client.done) seeding++; else downloading++; // active++; } listModel.addElement("All (" + size + ")"); listModel.addElement("Downloading (" + downloading + ")"); listModel.addElement("Seeding (" + seeding + ")"); // listModel.addElement("Active (" + active + ")"); // listModel.addElement("Inactive (" + inactive + ")"); list.setSelectedIndex(idx); } private String sizeToString(long size) { if (size < 1024 * 1024) return "" + size/1024 + "KBs"; if (size < 1024 * 1024 * 1024) return "" + size/(1024 * 1024) + "MBs"; return "" + size/(1024 * 1024 * 1024) + "GBs"; } private String calcETA(TorrentClient client) { if (client.totalLength == client.downAmount) return "Done"; int downSpeed = client.downSpeed; if (downSpeed == 0) return "inf"; int seconds = (int)((client.totalLength - client.downAmount) / downSpeed); int minutes = seconds / 60; seconds = seconds - (minutes * 60); int hours = minutes / 60; minutes = minutes - (hours * 60); return String.format("%02d:%02d:%02d", hours,minutes,seconds); } private void addRow(TorrentClient client, int idx) { //name, #, size, done, status, seeds, peers, downSpeed, upSpeed, ETA, uploaded, ratio, available client.reset(); tableModel.addRow(new Object[] { client.name, idx, sizeToString(client.totalLength), "" + client.downAmount * 100 / client.totalLength + "%", client.status, client.seeders, client.getNumPeers(), sizeToString(client.downSpeed), sizeToString(client.upSpeed), calcETA(client), sizeToString(client.upAmount), "" + client.upAmount / client.downAmount, "" + client.available }); table.repaint(); } private void updateRow(TorrentClient client, int row) { //name, #, size, done, status, seeds, peers, downSpeed, upSpeed, ETA, uploaded, ratio, available client.update(); table.setValueAt("" + client.downAmount * 100 / client.totalLength + "%", row, 3); table.setValueAt(client.status, row, 4); table.setValueAt("" + client.seeders, row, 5); table.setValueAt(client.getNumPeers(), row, 6); table.setValueAt(sizeToString(client.downSpeed), row, 7); table.setValueAt(sizeToString(client.upSpeed), row, 8); table.setValueAt(calcETA(client), row, 9); table.setValueAt(sizeToString(client.upAmount), row, 10); table.setValueAt("" + client.upAmount / client.downAmount, row, 11); table.setValueAt("" + client.available, row, 12); } private void updateTable() { tableModel.setRowCount(0); int idx = list.getSelectedIndex(); if (idx == -1) return; int size = clients.size(); for(int a=0;a<size;a++) { TorrentClient client = clients.get(a); switch (idx) { case 0: addRow(client, a); break; case 1: if (!client.done) addRow(client, a); break; case 2: if (client.done) addRow(client, a); break; } } } private void addTorrent(String file, String dest) { Torrent newTorrent = new Torrent(); newTorrent.file = file; newTorrent.dest = dest; newTorrent.active = true; newTorrent.paused = false; config.torrent = Arrays.copyOf(config.torrent, config.torrent.length + 1); config.torrent[config.torrent.length-1] = newTorrent; saveConfig(); } private void removeTorrent(int idx) { int len = config.torrent.length; Torrent newList[] = new Torrent[len-1]; System.arraycopy(config.torrent, 0, newList, 0, idx); System.arraycopy(config.torrent, idx+1, newList, idx, len - idx - 1); config.torrent = newList; saveConfig(); } private void addFile() { JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setMultiSelectionEnabled(false); chooser.setCurrentDirectory(new File(JF.getUserPath() + "/Torrents")); javax.swing.filechooser.FileFilter ffTorrent = new javax.swing.filechooser.FileFilter() { public boolean accept(File file) { if (file.isDirectory()) return true; if (file.getName().endsWith(".torrent")) return true; return false; } public String getDescription() { return "Torrent (*.torrent)"; } }; chooser.addChoosableFileFilter(ffTorrent); chooser.setFileFilter(ffTorrent); // chooser.setFileFilter(todo); if (chooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) return; File torrent = chooser.getSelectedFile(); chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); chooser.setMultiSelectionEnabled(false); chooser.setCurrentDirectory(new File(JF.getUserPath() + "/Downloads")); if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return; File dest = chooser.getSelectedFile(); if (!startTorrent(torrent.getAbsolutePath(), dest.getAbsolutePath(), true, false)) return; addTorrent(torrent.getAbsolutePath(), dest.getAbsolutePath()); } private String errmsg; private File urltorrent; private String getNameFromURL(String url) { int idx1 = url.lastIndexOf('/'); int idx2 = url.lastIndexOf('.'); if (idx2 == -1) idx2 = url.length(); return url.substring(idx1+1, idx2); } private void addURL() { String urlStr = JF.getString("Enter HTTP[S] URL:", ""); if (urlStr == null) return; boolean http = false; boolean https = false; if (urlStr.startsWith("http://")) http = true; if (urlStr.startsWith("https://")) https = true; if (!http && !https) { JF.showError("Error", "Unsupported URL"); return; } try { JFTask task = new JFTask() { public boolean work() { try { String urlString = (String)this.getProperty("url"); this.setLabel("Downloading : " + urlString); this.setProgress(5); // int idx = urlString.lastIndexOf("."); // String ext = urlString.substring(idx).toLowerCase(); urltorrent = new File(JF.getUserPath() + "/Torrents/" + getNameFromURL(urlString) + ".torrent"); URL url = new URL(urlString); HttpURLConnection uc = (HttpURLConnection)url.openConnection(); this.setProgress(25); uc.connect(); InputStream fis = uc.getInputStream(); FileOutputStream fos = new FileOutputStream(urltorrent); JFLog.log("size=" + fis.available()); if (uc.getResponseCode() != 200) throw new Exception("Error:" + uc.getResponseCode() + ":" + uc.getResponseMessage()); long length = uc.getContentLength(); if (length <= 0) throw new Exception("unknown length"); if (!JF.copyAll(fis, fos, length)) throw new Exception("download failed"); fis.close(); fos.close(); this.setProgress(50); this.setLabel("Complete"); this.setProgress(100); errmsg = null; return true; } catch (Exception e) { errmsg = e.toString(); return false; } } }; task.setProperty("url", urlStr); ProgressDialog dialog = new ProgressDialog(null, true, task); dialog.setVisible(true); if (errmsg != null) { JF.showError("Error", "Exception:" + errmsg); } } catch (Exception e) { JF.showError("Error", "Exception:" + e); } JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); chooser.setMultiSelectionEnabled(false); chooser.setCurrentDirectory(new File(JF.getUserPath() + "/Downloads")); if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return; File dest = chooser.getSelectedFile(); if (!startTorrent(urltorrent.getAbsolutePath(), dest.getAbsolutePath(), true, false)) return; addTorrent(urltorrent.getAbsolutePath(), dest.getAbsolutePath()); } /** This allows connections to untrusted hosts. */ private void initHttps() { TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {} public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {} } }; // Let us create the factory where we can set some parameters for the connection try { SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); SSLSocketFactory sslsocketfactory = (SSLSocketFactory) sc.getSocketFactory(); //this method will work with untrusted certs } catch (Exception e) { JFLog.log(e); } } public void close() { for(int a=0;a<clients.size();a++) { clients.get(a).close(); } } private void updateGUI() { int size = table.getRowCount(); for(int a=0;a<size;a++) { int idx = (Integer)table.getValueAt(a, 1); updateRow(clients.get(idx), a); } table.repaint(); } public void setStatus(String txt) { status.setText("Status : " + txt); } }