Package nixonftp

Source Code of nixonftp.NXFtpClient

/* nixonFTP
* FTP client version 0.1
* Copyright (C) 2010 NIXON Development Corporation.
* All rights reserved.
* http://members.shaw.ca/nixon.com
*/
package nixonftp;

import nixonftp.error.NXLoginException;
import nixonftp.error.NXProtocolException;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import sun.net.ftp.FtpClient;
import sun.net.ftp.FtpLoginException;
import sun.net.ftp.FtpProtocolException;

public class NXFtpClient extends FtpClient {

  private String[] arrCredentials;
  private HashMap<String, NXObjectIndex> objectIndex = new HashMap<String, NXObjectIndex>();
  private String dirListing = "";
  static int FTP_SUCCESS = 1;
  static int FTP_TRY_AGAIN = 2;
  static int FTP_ERROR = 3;
  private String serverName;
  String command;
  private boolean replyPending = false;
  private boolean binaryMode = false;
  private boolean enableLog = false;
  private NXLog log;
  private int lastReplyCode;
  private int port;
 
  public NXFtpClient() {
    super();
    connectTimeout = 15000;
    defaultConnectTimeout = 15000;
  }

  public NXFtpClient(NXLog log, Proxy proxy) {
    super(proxy);
    this.log = log;
    enableLog = true;
    connectTimeout = 15000;
    defaultConnectTimeout = 15000;
  }

  public String getResponseString() {
    String response = (String) serverResponse.elementAt(0);
    return response;
  }

  @Override
  public int readServerResponse() throws IOException {
    StringBuffer replyBuf = new StringBuffer(32);
    int c;
    int continuingCode = -1;
    int code;
    String response;
    serverResponse.setSize(0);
    while (true) {
      while ((c = serverInput.read()) != -1) {
        if (c == '\r') {
          if ((c = serverInput.read()) != '\n') {
            replyBuf.append('\r');
          }
        }
        replyBuf.append((char) c);
        if (c == '\n') {
          break;
        }
      }
      response = replyBuf.toString();
      replyBuf.setLength(0);
      String strLog;
      strLog = response;
      if (response.length() == 0) {
        code = -1;
      } else {
        try {
          code = Integer.parseInt(response.substring(0, 3));
          if (code >= 500) {
            strLog = '\u3000' + response;
          } else if (code >= 400) {
            strLog = '\u3001' + response;
          } else if (code >= 300) {
            strLog = '\u3002' + response;
          } else if (code >= 200) {
            strLog = '\u3003' + response;
          } else {
            strLog = '\u3004' + response;
          }
        } catch (NumberFormatException e) {
          code = -1;
        } catch (StringIndexOutOfBoundsException e) {
          /* this line doesn't contain a response code, so
          we just completely ignore it */
          continue;
        }
      }
      if (enableLog) {
        log.add(strLog);
      }
      serverResponse.addElement(response);
      if (continuingCode != -1) {
        /* we've seen a XXX- sequence */
        if (code != continuingCode ||
              (response.length() >= 4 && response.charAt(3) == '-')) {
          continue;
        } else {
          /* seen the end of code sequence */
          continuingCode = -1;
          break;
        }
      } else if (response.length() >= 4 && response.charAt(3) == '-') {
        continuingCode = code;
        continue;
      } else {
        break;
      }
    }
    return lastReplyCode = code;
  }

  public boolean getBinary() {
    return binaryMode;
  }

  protected int issueCommand(String s) throws IOException {
    String p = "PASS";
    if (s.contains(p)) {
      if (enableLog) {
        log.add(p);
      }
    } else {
      if (enableLog) {
        log.add(s);
      }
    }
    return super.issueCommand(s);
  }

  @Override
  protected void issueCommandCheck(String cmd) throws IOException {
    if (issueCommand(cmd) != FTP_SUCCESS) {
      String s = getResponseString();
      if (s.startsWith("421")) {
        //closeServer();
        serverSocket = null;
        serverInput = null;
        serverOutput = null;
        connect();
        issueCommand(cmd);
      } else {
        throw new IOException(cmd + ":" + getResponseString());
      }
    }
  }

  protected Socket openPassiveDataConnection() throws IOException {
    String serverAnswer;
    int port;
    InetSocketAddress dest = null;

    /**
     * Here is the idea:
     *
     * - First we want to try the new (and IPv6 compatible) EPSV command
     *   But since we want to be nice with NAT software, we'll issue the
     *   EPSV ALL cmd first.
     *   EPSV is documented in RFC2428
     * - If EPSV fails, then we fall back to the older, yet OK PASV command
     * - If PASV fails as well, then we throw an exception and the calling method
     *   will have to try the EPRT or PORT command
     */
    if (issueCommand("PASV") == FTP_SUCCESS) {
      // EPSV ALL failed, so Let's try the regular PASV cmd

      serverAnswer = getResponseString();

      // Let's parse the response String to get the IP & port to connect to
      // the String should be in the following format :
      //
      // 227 Entering Passive Mode (A1,A2,A3,A4,p1,p2)
      //
      // Note that the two parenthesis are optional
      //
      // The IP address is A1.A2.A3.A4 and the port is p1 * 256 + p2
      //
      // The regular expression is a bit more complex this time, because the
      // parenthesis are optionals and we have to use 3 groups.

      Pattern p = Pattern.compile("227 .* \\(?(\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3}),(\\d{1,3}),(\\d{1,3})\\)?");
      Matcher m = p.matcher(serverAnswer);
      if (!m.find()) {
        throw new NXProtocolException("PASV failed : " + serverAnswer);
      }
      // Get port number out of group 2 & 3
      port = Integer.parseInt(m.group(3)) + (Integer.parseInt(m.group(2)) << 8);
      // IP address is simple
      String s = m.group(1).replace(',', '.');
      dest = new InetSocketAddress(s, port);
    } else if (issueCommand("EPSV ALL") == FTP_SUCCESS) {
      // We can safely use EPSV commands
      if (issueCommand("EPSV") == FTP_ERROR) {
        throw new NXProtocolException("EPSV Failed: " + getResponseString());
      }
      serverAnswer = getResponseString();

      // The response string from a EPSV command will contain the port number
      // the format will be :
      //  229 Entering Extended Passive Mode (|||58210|)
      //
      // So we'll use the regular expresions package to parse the output.

      Pattern p = Pattern.compile("^229 .* \\(\\|\\|\\|(\\d+)\\|\\)");
      Matcher m = p.matcher(serverAnswer);
      if (!m.find()) {
        throw new NXProtocolException("EPSV failed : " + serverAnswer);
      }
      // Yay! Let's extract the port number
      String s = m.group(1);
      port = Integer.parseInt(s);
      InetAddress add = serverSocket.getInetAddress();
      if (add != null) {
        dest = new InetSocketAddress(add, port);
      } else {
        // This means we used an Unresolved address to connect in
        // the first place. Most likely because the proxy is doing
        // the name resolution for us, so let's keep using unresolved
        // address.
        dest = InetSocketAddress.createUnresolved(serverName, port);
      }
    }
    // Got everything, let's open the socket!
    Socket s;

    if (proxy != null) {
      if (proxy.type() == Proxy.Type.SOCKS) {
        s = AccessController.doPrivileged(
              new PrivilegedAction<Socket>() {

                public Socket run() {
                  return new Socket(proxy);
                }
              });
      } else {
        s = new Socket(Proxy.NO_PROXY);
      }
    } else {
      s = new Socket();
    }
    if (connectTimeout >= 0) {
      s.connect(dest, connectTimeout);
    } else {
      if (defaultConnectTimeout > 0) {
        s.connect(dest, defaultConnectTimeout);
      } else {
        s.connect(dest);
      }
    }
    if (readTimeout >= 0) {
      s.setSoTimeout(readTimeout);
    } else if (defaultSoTimeout > 0) {
      s.setSoTimeout(defaultSoTimeout);
    }
    return s;
  }

  public void setCredentials(String[] argv) {
    arrCredentials = argv;
  }

  public String[] getCredentials() {
    return arrCredentials;
  }

  private int parsePort(String addr) {
    int pos = addr.indexOf(":");
    int ret = -1;
    if (pos != -1) {
      ret = Integer.parseInt(addr.substring(pos + 1));
    }
    return ret;
  }

  public void connect() throws FtpLoginException, FtpProtocolException, UnknownHostException, IOException {
    NXObjectIndex oi = new NXObjectIndex('d', "/", "", "", "", -1, -1, new Date(0));
    objectIndex.put("/", oi);
    if (arrCredentials[0].equals("")) {
      arrCredentials[0] = "127.0.0.1";
    }
    int port = parsePort(arrCredentials[0]);
    String server = arrCredentials[0];
    if (port != -1) {
      server = arrCredentials[0].substring(0, arrCredentials[0].indexOf(":"));
      System.out.println("Using port " + port);
    } else {
      port = 21;
    }
    this.port = port;
    openServer(server, port);
    if (arrCredentials[1].equals("")) {
      arrCredentials[1] = "anonymous";
      arrCredentials[2] = "ftp@nixon.com";
    }
    login(arrCredentials[1], arrCredentials[2]);
    indexDirectory("/");
  }

  String getListingAsString() throws IOException, NXProtocolException, NXLoginException {
    InputStream ls = list();
    BufferedInputStream bls = new BufferedInputStream(ls);

    /*OutputStream os = new FileOutputStream("test.text");
    BufferedOutputStream bos = new BufferedOutputStream(os);*/
    ByteArrayOutputStream baols = new ByteArrayOutputStream();

    byte[] buffer = new byte[1024];
    int readCount;

    while ((readCount = ls.read(buffer)) > 0) {
      baols.write(buffer, 0, readCount);
    }

    ls.close();

    return baols.toString();
  }

  @SuppressWarnings("empty-statement")
  public int indexDirectory(String dir) {
    try {
      cd(dir);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    NXObjectIndex blankObject = new NXObjectIndex('d', "/", "", "", "", -1, -1, new Date(0));
    objectIndex.put(dir, blankObject);

    String[] listing = null;
    String all = null;
   
    try {
      all = getListingAsString();
      listing = all.split("\n");
    } catch (IOException ex) {
      ex.printStackTrace();
    }
   

    char type;
    String name;
    int hardLinks;
    String permissions;
    String owner = null;
    String group = null;
    long size = 0;
    Date date;
    int arrow = 0;
    int idxSpace;
    String real = null;

    for (int x = 0; x < listing.length; x++) {
      try {
        type = listing[x].charAt(0);
        permissions = listing[x].substring(1, 10);
        listing[x] = listing[x].substring(10).trim();

        idxSpace = listing[x].indexOf(" ");
        String strHardLinks = listing[x].substring(0, idxSpace);
        hardLinks = Integer.valueOf(strHardLinks);

        for (int y = 0; y < 3; y++) {
          listing[x] = listing[x].substring(idxSpace).trim();
          idxSpace = listing[x].indexOf(" ");
          String item = listing[x].substring(0, idxSpace);
          listing[x] = listing[x].substring(idxSpace + 1).trim();
          idxSpace = 0;

          switch (y) {
            case 0:
              owner = item;
              break;
            case 1:
              group = item;
              break;
            case 2:
              size = Long.valueOf(item);
              break;
          }
        }

        String strDate = listing[x].trim().substring(0, 12).trim();
        date = parseDate(strDate);

        name = listing[x].substring(12).trim();

        if (name.equals(".") || name.equals("..")) continue;
       
        if (type == 'l') {
          arrow = name.indexOf("->");
          if (arrow != -1) {
            real = name.substring(arrow + 3);
            name = name.substring(0, arrow - 1);
          }
        }
        NXObjectIndex obj = new NXObjectIndex(type, name, permissions, owner, group, size, hardLinks, date);
        obj.setRealLocation(real);
        NXObjectIndex dirObj = (NXObjectIndex) objectIndex.get(dir);
        dirObj.objects.put(name, obj);
      } catch (Exception ex) {
        System.out.println("Error in IndexDirectory: " + ex.toString());
      }
    }
    return all.length();
  }

  public void fakeDirectory(NXObjectIndex oi, String path) { //used for links
    objectIndex.put(path, oi);
  }

  public boolean isDirectory(String dir) {
    boolean isLinkDir = false;
    try {
      isLinkDir = this.sendCommand("CWD " + dir);
    } catch (FileNotFoundException ex) {
      isLinkDir = false;
    } catch (IOException ex) {

    }
    return isLinkDir;
  }

  private Date parseDate(String date) {
    String temp;
    int month = 0;
    int day;
    int year;
    int hour;
    int minute;
    String[] months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

    Calendar cal = Calendar.getInstance();
    year = cal.get(Calendar.YEAR);
    int currMonth = cal.get(Calendar.MONTH);
    cal.clear();


    temp = date.substring(0, 3); //get month
    for (int x = 0; x < months.length; x++) {
      if (months[x].equals(temp)) {
        month = x;
      }
    }

    temp = date.substring(4, 6);
    day = Integer.parseInt(temp.trim());

    if (date.contains(":")) { //includes time
      hour = Integer.parseInt(date.substring(8, 9));
      minute = Integer.parseInt(date.substring(11));
      int actualYear;
      if (month > currMonth) {
        actualYear = year - 1;
      } else {
        actualYear = year;
      }
      cal.set(actualYear, month, day, hour, minute);
    } else {
      year = Integer.parseInt(date.substring(8));
      cal.set(year, month, day);
    }
    return cal.getTime();
  }

  public boolean sendCommand(String cmd) throws IOException {
    issueCommand(cmd);
    return isValidResponse();
  }

  private boolean isValidResponse() {
    try {
      int respCode = getResponseCode();
      return (respCode >= 200 && respCode < 300);
    } catch (Exception e) {
      return false;
    }
  }

  public int getResponseCode() throws NumberFormatException {
    return Integer.parseInt(getResponseString().substring(0, 3));
  }

  HashMap getObjectIndex() {
    return objectIndex;
  }
}
TOP

Related Classes of nixonftp.NXFtpClient

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.