Package crushftp.server

Source Code of crushftp.server.Lister

package crushftp.server;

import java.io.*;
import java.net.*;
import java.util.*;
import java.text.SimpleDateFormat;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import crushftp.handlers.*;
import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;

import crushftp.gui.LOC;

public class ServerSessionHTTP implements Runnable
{
  static RandomAccessFile log = null;
  static Properties proppatches = null;
  static Properties locktokens = null;
  static Properties publicpasswords = null;
  public int bufferSize = 32768;
  byte headerBytes[] = new byte[bufferSize];
  public ServerSession thisSession = null;
  public Thread this_thread = null;
  public Socket sock = null;
  public OutputStream original_os = null;
  public BufferedInputStream original_is = null;
  public boolean keepGoing = true;
  SimpleDateFormat lastModifiedSDF = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z",Locale.US);
  int timeoutSeconds = 300;
  boolean done = false;
  boolean kill_all = false;
  RETR_handler retr = new RETR_handler();
  STOR_handler stor = new STOR_handler();
  Thread stor_Thread = null;
  String cacheHeader = "";
  Properties globalSessions = null;
  boolean writeCookieAuth = false;
  SAXBuilder sax = new SAXBuilder();
  XMLOutputter xmlOut = null;
  SimpleDateFormat sdf_rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z",Locale.US);
  SimpleDateFormat sdf_rfc1123_2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'",Locale.US);
  String hostString = "";
  String domain = "";
  Properties server_item;
  String proxy = "";
  long mimesModified = 0;
  Properties mimes = new Properties();
  String server_header = "AppleDotMacServer-1B5411";

  String CRLF = "\r\n";
  Common common_code = null;
  ServerStatus server_status_frame = null;
  boolean sniffer = false;
  ServerSessionNotMacXML ssnmx = new ServerSessionNotMacXML();
  String userAgent = "";
  Properties dns = new Properties();

  public ServerSessionHTTP(Socket sock, ServerStatus server_status_frame, int user_number, String user_ip, int listen_port, String listen_ip, String listen_ip_port, Properties server_item, Properties linked_server)
  {
    dns.put("WWW.MAC.COM","17.250.248.32");
    dns.put("HOMEPAGE.MAC.COM","17.250.248.34");
    dns.put("IDISK.MAC.COM","17.250.248.77");
    dns.put("CONFIGURATION.APPLE.COM","17.250.248.105");
    dns.put("SYNCMGMT.MAC.COM","17.250.248.103");

    this.server_status_frame = server_status_frame;
    //server_header = "CrushFTP " + server_status_frame.siSG("version_info_str");
    this.sock = sock;
    this.server_item = server_item;
    if (System.getProperties().get("httpSessions") == null) System.getProperties().put("httpSessions", new Properties());
    globalSessions = (Properties)System.getProperties().get("httpSessions");
    thisSession = new ServerSession(sock, server_status_frame, user_number, user_ip, listen_port, listen_ip, listen_ip_port, server_item, linked_server);
    common_code = thisSession.common_code;
    thisSession.give_thread_pointer(Thread.currentThread());
    thisSession.uiPUT("dont_read","true");
    thisSession.uiPUT("dont_write","true");
    proxy = thisSession.server_item.getProperty("httpReverseProxy","");
    if (!proxy.startsWith("/"))proxy="/"+proxy;if (proxy.endsWith("/"))proxy=proxy.substring(0,proxy.length()-1);
  }

  public void run()
  {
    try
    {
      if (log == null)
      {
        if (new File("./").getCanonicalPath().toUpperCase().indexOf("NOTMAC") >= 0 || System.getProperty("crushftp.home").toUpperCase().indexOf("NOTMAC") >= 0)
        {
          try{log = new RandomAccessFile("/Library/Application Support/NotMac/NotMac_"+new Date().getTime()+".log","rw");}catch(Exception e){e.printStackTrace();};
        }
      }
      thisSession.add_log("["+server_item.getProperty("serverType","ftp")+":"+server_item.getProperty("port","21")+"][" + thisSession.uiSG("user_number") + "] "+SG("Accepting connection from")+": " + thisSession.uiSG("user_ip") + ":" + sock.getPort() + CRLF, "ACCEPT");
      thisSession.uiPUT("login_date",new Date().toString());
      server_status_frame.hold_user_pointer(thisSession.user_info);

      thisSession.thread_killer_item = new IdlerKiller(thisSession, new Date().getTime(),2, Thread.currentThread());
      original_os = sock.getOutputStream();
      original_is = new BufferedInputStream(sock.getInputStream());
      while(sock != null && sock.isConnected() && !done)
      {
        Thread.sleep(thisSession.delayInterval);
        keepGoing = true;
        if (thisSession.uiBG("refresh_user"))
        {
          thisSession.uiPUT("refresh_user","false");
          thisSession.uVFS = null;
          if (!thisSession.verify_user(thisSession.uiSG("user_name"),thisSession.uiSG("current_password"))) break;
        }
        handle_http_requests();
      }
//      if (kill_all) server_status_frame.kill_same_name_same_ip(thisSession.user_info);
      if (sock != null) sock.close();
    }
    catch(Exception e)
    {
      Common.debug(1,e);
      thisSession.uiPUT("dieing","true");
    }
    if (!thisSession.uiBG("didDisconnect"))
    {
      thisSession.uiPUT("didDisconnect","true");
      thisSession.do_event("Disconnected.", "QUIT","");
    }
    thisSession.add_log("[" + thisSession.uiSG("user_number") + ":" + thisSession.uiSG("user_name") + ":" + thisSession.uiSG("user_ip") + "] *"+SG("Disconnected")+".*", "QUIT");
    thisSession.uiPUT("dieing","true");
    do_kill();
  }

  public void give_thread_pointer(Thread this_thread)
  {
    this.this_thread = this_thread;
    thisSession.this_thread = this_thread;
  }

  public void do_kill()
  {
    stor.die_now = true;
    if (stor_Thread != null) stor_Thread.interrupt();
    addSessionCommand("QUIT","");
    thisSession.do_kill();
  }

  public void doSniffer(Vector headers)
  {
    int port = 443;
    String headersStr = "";
    for (int x=0; x<headers.size(); x++)
    {
      String data = headers.elementAt(x).toString();
      if (data.toUpperCase().startsWith("HOST: "))
      {
        hostString = data.substring(data.toUpperCase().indexOf(" ")+1).trim();
        thisSession.uiPUT("listen_ip",hostString);//first format "127.0.0.1", second format is "127.0.0.1:80"
        if (data.indexOf(":",data.indexOf(" ")) >= 0) thisSession.uiPUT("listen_ip",data.substring(data.indexOf(" ")+1,data.indexOf(":",data.indexOf(" "))).trim());
        domain = hostString;
        if (domain.indexOf(":") >= 0) domain = domain.substring(0,domain.indexOf(":"));
        if (data.toUpperCase().startsWith("X-FORWARDED-HOST: ") && thisSession.uiSG("user_ip").equals("127.0.0.1")) thisSession.uiPUT("user_ip",domain);
        port = sock.getLocalPort();

      }
      if (!data.startsWith("Accept-Encoding") && !data.startsWith("X-"))
      {
        if (data.startsWith("Connection")) headersStr += "Connection: close\r\n";
        else headersStr += data + "\r\n";
      }
    }
    thisSession.server_status_frame.append_log("**************************************************************\r\n"+headersStr,"ACCEPT",thisSession);
    try
    {
      if (log != null) log.write(headersStr.getBytes());
      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) {}
      }};

      Socket sockOut = new Socket(dns.getProperty(domain.toUpperCase()), port);
      if (port == 443)
      {
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        sockOut = (SSLSocket)sc.getSocketFactory().createSocket(sockOut,domain,port,true);
        ((SSLSocket)sockOut).setUseClientMode(true);
        ((SSLSocket)sockOut).startHandshake();
      }

      class passthrough implements Runnable
      {
        InputStream in;
        OutputStream out;
        String id;
        public passthrough(String id, InputStream in, OutputStream out)
        {
          this.in= in;
          this.out = out;
          this.id = id;
        }
        public void run()
        {
          byte b[] = new byte[32768];
          int bytes = 0;
          try
          {
            while(bytes >= 0)
            {
              bytes = in.read(b);
              if (bytes > 0)
              {
                out.write(b,0,bytes);
                if (log != null) log.write(b,0,bytes);
                thisSession.server_status_frame.append_log("*****************************"+id+"*********************************\r\n"+new String(b,0,bytes),"ACCEPT",thisSession);
                out.flush();
              }
            }
          }
          catch(Exception e)
          {
            e.printStackTrace();
          }
          try {in.close();}catch(Exception e) {}
          try {out.close();}catch(Exception e) {}
        }
      }
      sockOut.getOutputStream().write(headersStr.getBytes());
      sockOut.getOutputStream().write("\r\n".getBytes());
      sockOut.getOutputStream().flush();
      new Thread(new passthrough("WROTE",sock.getInputStream(),sockOut.getOutputStream())).start();
      Thread t = new Thread(new passthrough("READ",sockOut.getInputStream(),sock.getOutputStream()));
      t.start();
      t.join();
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
    done = true;
  }

  public void handle_http_requests() throws Exception
  {
    if (proppatches == null && new File(System.getProperty("crushftp.backup")+"backup/proppatches.prop").exists())
    {
      ObjectInputStream ois = new ObjectInputStream(new FileInputStream(System.getProperty("crushftp.backup")+"backup/proppatches.prop"));
      proppatches = (Properties)ois.readObject();
      ois.close();
    }
    if (proppatches == null){proppatches = new Properties();}

    if (locktokens == null && new File(System.getProperty("crushftp.backup")+"backup/locktokens.prop").exists())
    {
      ObjectInputStream ois = new ObjectInputStream(new FileInputStream(System.getProperty("crushftp.backup")+"backup/locktokens.prop"));
      locktokens = (Properties)ois.readObject();
      ois.close();
    }
    if (locktokens == null){locktokens = new Properties();}

    if (publicpasswords == null && new File(System.getProperty("crushftp.backup")+"backup/publicpasswords.prop").exists())
    {
      ObjectInputStream ois = new ObjectInputStream(new FileInputStream(System.getProperty("crushftp.backup")+"backup/publicpasswords.prop"));
      publicpasswords = (Properties)ois.readObject();
      ois.close();
    }
    if (publicpasswords == null){publicpasswords = new Properties();}

    String data = "";
    Vector headers = getHeaders();
    try
    {
      if (headers.size() > 0)
      {
        data = headers.elementAt(0).toString();
        data = Common.url_decode(data);
        data = Common.replace_str(data,"..","");
        data = Common.replace_str(data,"\\","/");
        data = Common.replace_str(data,"//","/");
        boolean ok = false;
        if (data.toUpperCase().startsWith("GET /WEBINTERFACE/")
            || data.toUpperCase().startsWith("GET /FAVICON.ICO")
            || data.toUpperCase().startsWith("GET /CRUSHFTP.JAR")
            || data.toUpperCase().startsWith("HEAD /CRUSHFTP.JAR")) ok = true;
        if (data.toUpperCase().startsWith("GET /WEBINTERFACE/CRUSHFTP.JNLP")) ok = false;
        if (data.toUpperCase().startsWith("GET /WEBINTERFACE/LOGIN.HTML?")) ok = false;
        if (data.toUpperCase().indexOf("/CRUSHIMAGEPREVIEW") >= 0) ok = false;
        if (ok)
        {
          ServerSessionHTTPWI sswi = new ServerSessionHTTPWI(this,headers,original_os);
          sswi.serveFile();
          return;
        }

        processMiniURLs(data,headers);
      }
    }
    catch (Exception e)
    {
      Common.debug(1,e);
    }

    if (done) return;
    String user_dir = "/";
    boolean ignoreAuth = false;
    boolean forceFileName = false;
    long http_len_max = 0;
    cacheHeader = "";
    thisSession.uiPUT("start_resume_loc","0");
    thisSession.uiPUT("byteRanges",new Vector());

    if (thisSession.server_item.getProperty("https_redirect","false").equalsIgnoreCase("true") && thisSession.server_item.getProperty("serverType","FTP").toUpperCase().equals("HTTP"))
    {
      String path = headers.elementAt(0).toString();
      int endPos = path.lastIndexOf(" HTTP");
      if (endPos < 0) endPos = path.length()-1;
      path = path.substring(path.indexOf(" ")+1, endPos);
      sendHttpsRedirect(path,headers);
      write_command_http("Connection: close");
      write_command_http("");
      kill_all = true;
      done = true;
      return;
    }
    for (int x=0; x<headers.size(); x++) //first loop through and see if they have a cookie for auth
    {
      data = headers.elementAt(x).toString();
      if (data.toUpperCase().startsWith("HOST: ") || data.toUpperCase().startsWith("X-FORWARDED-HOST: "))
      {
        hostString = data.substring(data.toUpperCase().indexOf(" ")+1).trim();
        thisSession.uiPUT("listen_ip",hostString);//first format "127.0.0.1", second format is "127.0.0.1:80"
        if (data.indexOf(":",data.indexOf(" ")) >= 0) thisSession.uiPUT("listen_ip",data.substring(data.indexOf(" ")+1,data.indexOf(":",data.indexOf(" "))).trim());
        domain = hostString;
        if (domain.indexOf(":") >= 0) domain = domain.substring(0,domain.indexOf(":"));
        if (data.toUpperCase().startsWith("X-FORWARDED-HOST: ") && thisSession.uiSG("user_ip").equals("127.0.0.1")) thisSession.uiPUT("user_ip",domain);
      }
      if (data.startsWith("User-Agent: "))
      {
        userAgent = data.substring("User-Agent: ".length()).trim();
      }
      else if (data.startsWith("X-Forwarded-For: "))
      {
        thisSession.uiPUT("user_ip",data.substring(data.indexOf(":")+1).trim());
      }
    }
    if ((hostString.equals("www.mac.com") && sock.getLocalPort() == 80) || (hostString.equals("homepage.mac.com") && sock.getLocalPort() == 80))// || crushftp.gui.MainFrame.scroll_activity_cb.isSelected())
    {
      //http://homepage.mac.com/username/
      //is this user a valid notMac user?  If not, then forward them.  If so, then serve the pages.
      boolean ok = true;
      String data0 = headers.elementAt(0).toString();
      data0 = data0.substring(data0.indexOf(" ")+2);
      if (data0.indexOf("/") >= 0)
      {
        data0 = data0.substring(0,data0.indexOf("/"));
        if (!data0.equals("") && new File("/Library/Application Support/NotMac/Storage/"+data0+"/").exists()) ok = false;
      }
      if (ok)
      {
        data = headers.elementAt(0).toString();
        data = data.substring(data.indexOf(" ")+1, data.lastIndexOf(" "));
        //write_command_http("HTTP/1.0 302 Redirect");
        //write_command_http("Pragma: no-cache");
        //get host string to put in location.
        String baseURL = getBaseUrl(headers);
        baseURL = Common.replace_str(baseURL,domain,dns.getProperty(domain.toUpperCase(),domain));
        //write_command_http("location: "+baseURL+data);
        //write_command_http("");
        doSniffer(headers);
        return;
      }
    }
    for (int x=0; x<headers.size(); x++) //first loop through and see if they have a cookie for auth
    {
      data = headers.elementAt(x).toString();
      if (data.startsWith("Cookie: "))
      {
        if (data.indexOf("CrushAuth=") >= 0)
        {
          String authorization = data.substring(data.indexOf("CrushAuth=")+"CrushAuth=".length());
          if (authorization.indexOf("; ") >= 0) authorization = authorization.substring(0,authorization.indexOf("; "));
          if (authorization.equals("login"))
          {
            DEAUTH();
            kill_all = true;
            done = true;
            return;
          }
          else if (authorization.startsWith("logout"))
          {
            String sessionid = authorization.substring("logout".length());
            globalSessions.remove(thisSession.uiSG("user_ip")+"_"+sessionid+"_user");
            globalSessions.remove(thisSession.uiSG("user_ip")+"_"+sessionid+"_pass");

            sendRedirect("/",headers);
            write_command_http("Connection: close");
            write_command_http("Set-Cookie: CrushAuth=; path=/");
            thisSession.uiPUT("CrushAuth","");//needed to allow XML to work with Safari since it can't access cookies (CrushUpplet)
            write_command_http("");
            kill_all = true;
            done = true;
            thisSession.uVFS = null;
            return;
          }
          else if (authorization.equals("credentials"))
          {
            done = true;
            //let the auth headers below take care of this and set the sessionid in the cookie
            //or the POST LOGIN method below
          }
          else
          {
            //lookup in "globalSessions" using their IP and this sessionID
            //if we find it, get the user/pass out of it, and use it to re-auth them.
            try
            {
              String user = globalSessions.getProperty(thisSession.uiSG("user_ip")+"_"+authorization+"_user");
              String pass = globalSessions.getProperty(thisSession.uiSG("user_ip")+"_"+authorization+"_pass");
              thisSession.uiPUT("sessionID",authorization);
              if (user != null)
              {
                thisSession.uiPUT("user_name",user);
                thisSession.uiPUT("current_password",pass);
                thisSession.uiPUT("login_date_stamp",authorization);

                if (!thisSession.uiBG("user_logged_in") || thisSession.user.size() < 10)
                {
                  thisSession.uVFS = null;
                  thisSession.login_user_pass();
                }
                this_thread.setName(thisSession.uiSG("user_name") + ":(" + thisSession.uiSG("user_number") + ")-" + thisSession.uiSG("user_ip") + " (control)");

                //this token is 30 min old, accept it, but send a new cookie back updating the token time.
                if (new Date().getTime() - Long.parseLong(authorization) > 1000*60*30)
                {
                  globalSessions.remove(thisSession.uiSG("user_ip")+"_"+authorization+"_user");
                  globalSessions.remove(thisSession.uiSG("user_ip")+"_"+authorization+"_pass");
                  writeCookieAuth = true;
                  continue;
                }
                thisSession.uiPUT("CrushAuth",authorization);//needed to allow XML to work with Safari since it can't access cookies (CrushUpplet)
              }
            }
            catch(Exception e)
            {
              Common.debug(1,e);
            }
            writeCookieAuth = false;
            ignoreAuth = true;
          }
          fixRootDir(null);
        }
      }
    }
    if (!ignoreAuth)
    {
      for (int x=0; x<headers.size(); x++)
      {
        data = headers.elementAt(x).toString();
        if (data.startsWith("Authorization: ") && !thisSession.uiBG("user_logged_in"))
        {
          String authorization = data.substring("Authorization: Basic ".length());
          thisSession.uiPUT("current_password",thisSession.decode(authorization));
          thisSession.uiPUT("user_name",thisSession.uiSG("current_password").substring(0,thisSession.uiSG("current_password").indexOf(":")));
          thisSession.uiPUT("current_password",thisSession.uiSG("current_password").substring(thisSession.uiSG("current_password").indexOf(":") + 1));
          this_thread.setName(thisSession.uiSG("user_name") + ":(" + thisSession.uiSG("user_number") + ")-" + thisSession.uiSG("user_ip") + " (control)");
          thisSession.uVFS = null;
          boolean good = thisSession.login_user_pass();
          if (good)
          {
            thisSession.do_event("Logged In.", "PASS","");
            writeCookieAuth = true;
          }
        }
        else if (data.startsWith("GET /WebInterface/login.html?username=") || data.startsWith("POST /WebInterface/login.html?username=") && !thisSession.uiBG("user_logged_in"))
        {
          String autoUser = data.substring(data.indexOf("username=")+"username=".length());
          int endPos = data.lastIndexOf(" HTTP");
          if (endPos < 0) endPos = data.length()-1;
          String autoPass = data.substring(data.indexOf("password=")+"password=".length(), endPos)+"&";
          thisSession.uiPUT("user_name",autoUser.substring(0,autoUser.indexOf("&")));
          thisSession.uiPUT("current_password",autoPass.substring(0,autoPass.indexOf("&")));
          this_thread.setName(thisSession.uiSG("user_name") + ":(" + thisSession.uiSG("user_number") + ")-" + thisSession.uiSG("user_ip") + " (control)");
          thisSession.uVFS = null;
          boolean good = thisSession.login_user_pass();
          if (good)
          {
            String autoPath = "/";
            if (data.indexOf("&path=") >= 0) autoPath = data.substring(data.indexOf("&path=")+"&path=".length(), endPos);
            if (data.startsWith("GET ")) headers.setElementAt("GET "+autoPath+data.substring(endPos),x);
            else if (data.startsWith("POST ")) headers.setElementAt("POST "+autoPath+data.substring(endPos),x);
            forceFileName = true;
            thisSession.do_event("Logged In.", "PASS","");
            writeCookieAuth = true;
          }
        }
      }
    }
    //NotMac public folders password protection
    if(thisSession.uiSG("user_name").equalsIgnoreCase("public"))
    {
      data = headers.elementAt(0).toString();
      String data2 = data.substring(data.indexOf(" "),data.lastIndexOf(" ")).trim();
      String username = data2.substring(1,data2.indexOf("/",1));
      if (publicpasswords.containsKey(("/"+username+"/Public/").toUpperCase()))
      {
        if (data2.toUpperCase().indexOf("/PUBLIC/") >= 0)
        {
          String pass = Common.makeBoundary();
          try{pass = common_code.decode_pass(publicpasswords.getProperty(("/"+username+"/Public/").toUpperCase()));}catch(Exception e){}
          if (!pass.equals(thisSession.uiSG("current_password"))) DEAUTH();
        }
      }
    }

    //done with auth loop, now for the rest of the headerss
    for (int x=0; x<headers.size(); x++)
    {
      data = headers.elementAt(x).toString();
      int endPos = data.lastIndexOf(" HTTP");
      if (endPos < 0) endPos = data.length()-1;
      if (data.startsWith("Connection: "))
      {
        if (data.toUpperCase().indexOf("CLOSE") >= 0) done = true;//close the socket after the next thing we do.
      }
      else if (data.toUpperCase().startsWith("GET ") || data.toUpperCase().startsWith("HEAD "))
      {
        //special case for URL based login credentials
        if (data.toUpperCase().startsWith("GET /WEBINTERFACE/LOGIN.HTML?"))
        {
          data = data.substring(0,data.indexOf("?")) + data.substring(endPos);
          headers.setElementAt(data,x);
        }
        user_dir = data.substring(data.indexOf(" ")+1, endPos);
        if (user_dir.indexOf("\\") >= 0) user_dir = user_dir.replace('\\','/');
        if (!user_dir.startsWith("/")) user_dir = "/"+user_dir;
      }
      else if (data.toUpperCase().startsWith("POST ")|| data.toUpperCase().startsWith("PROPFIND ") || data.toUpperCase().startsWith("ACL ") || data.toUpperCase().startsWith("COPY "))
      {
        user_dir = data.substring(data.indexOf(" ")+1, endPos);
        if (user_dir.indexOf("\\") >= 0) user_dir = user_dir.replace('\\','/');
        if (!user_dir.startsWith("/")) user_dir = "/"+user_dir;
        if (!user_dir.endsWith("/")) user_dir += "/";
      }
      else if (data.toUpperCase().startsWith("OPTIONS "))
      {
        user_dir = data.substring(data.indexOf(" ")+1, endPos);
        if (user_dir.indexOf("\\") >= 0) user_dir = user_dir.replace('\\','/');
        if (!user_dir.startsWith("/")) user_dir = "/"+user_dir;
        if (!user_dir.endsWith("/")) user_dir += "/";

        write_command_http("HTTP/1.1 200 OK");
        write_command_http("Pragma: no-cache");
        write_command_http("x-responding-server: sslngn018");
        write_command_http("X-dmUser: "+SG("username"));
        write_command_http("MS-Author-Via: DAV");
        write_command_http("Allow: GET, HEAD, OPTIONS, PUT, POST, COPY, PROPFIND, DELETE, LOCK, MKCOL, MOVE, PROPPATCH, UNLOCK, ACL, DMMKPATH, DMMKPATHS, TRACE, DMPATCHPATHS");
        write_command_http("DAV: 1, 2, access-control, <http://apache.org/dav/propset/fs/1>");
        write_command_http("Content-Type: text/plain");
        write_command_http("Content-Length: 0");
        write_command_http("Connection: close");
        write_command_http("");
        keepGoing = false;
      }
      else if (data.toUpperCase().startsWith("CONTENT-LENGTH: "))
      {
        try{http_len_max = Long.parseLong(data.substring(data.toUpperCase().indexOf("CONTENT-LENGTH:") + "CONTENT-LENGTH:".length()).trim());}catch(Exception e){}
      }
    }
    thisSession.runPlugin("command",null);
    //log the command for later tracking
    try
    {
      String headersLine0 = headers.elementAt(0).toString();
      Properties p = new Properties();p.put("the_command",headersLine0.substring(0,headersLine0.indexOf(" ")));p.put("the_command_data",headersLine0.substring(headersLine0.indexOf(" ")+1,headersLine0.lastIndexOf(" ")));p.put("user_time",server_status_frame.logDateFormat.format(new Date()));p.put("display",p.getProperty("user_time")+" | "+thisSession.uiSG("the_command") + " " + p.getProperty("the_command_data",""));
      p.put("stamp",new Date().getTime()+"");
      thisSession.uiVG("session_commands").addElement(p);
    }
    catch(Exception e)
    {
      Common.debug(1,e);
    }
    if (!keepGoing)
    {
      if (http_len_max > 0) get_raw_http_command((int)http_len_max);
      done = true;
      return;
    }
    if (thisSession.uiSG("user_name").equals(""))
    {
      thisSession.uiPUT("user_name","anonymous");
      this_thread.setName(thisSession.uiSG("user_name") + ":(" + thisSession.uiSG("user_number") + ")-" + thisSession.uiSG("user_ip") + " (control)");
      thisSession.uVFS = null;
      thisSession.uiPUT("dont_log","true");
      thisSession.login_user_pass();
      if (thisSession.uiBG("user_logged_in")) writeCookieAuth = true;
      thisSession.uiPUT("dont_log","false");
      String attemptedPath = headers.elementAt(0).toString();
      attemptedPath = attemptedPath.substring(attemptedPath.indexOf(" ")+1,attemptedPath.lastIndexOf(" "));
      if (attemptedPath.toUpperCase().startsWith("/") && !attemptedPath.toUpperCase().startsWith(SG("root_dir").toUpperCase()) && thisSession.IG("max_logins") >= 0)
        attemptedPath = SG("root_dir") + attemptedPath.substring(1);
      try
      {
        String headersLine0 = headers.elementAt(0).toString();
        if ((thisSession.uVFS == null || thisSession.IG("max_logins") < 0) && !headersLine0.startsWith("PROPFIND")) //no anonymous user...make a fake area for anonymous
        {
          thisSession.uVFS = new VFS();
          if (thisSession.user != null) thisSession.user.put("root_dir","/");
          thisSession.uiPUT("user_logged_in","true");
          thisSession.uiPUT("user_name","");
          if (!headersLine0.toUpperCase().startsWith("GET /WEBINTERFACE/") && headersLine0.toUpperCase().startsWith("GET / "))
          {
            if (userAgent.toUpperCase().indexOf("IPHOTO") >= 0 || userAgent.toUpperCase().indexOf("ISNETSERVICES") >= 0)
            {
              thisSession.uiPUT("user_logged_in","false");
            }
            else
            {
              sendRedirect("/WebInterface/login.html",headers);
              write_command_http("Content-Length: 0");
              write_command_http("");
              return;
            }
          }
        }
        Properties testItem = thisSession.uVFS.get_item(attemptedPath);
        if (testItem == null && !(headersLine0.toUpperCase().startsWith("GET /WEBINTERFACE/")))
        {
          if (headersLine0.startsWith("PROPFIND") || headersLine0.startsWith("DELETE") || headersLine0.startsWith("PUT"))
          {
            thisSession.uiPUT("user_logged_in","false");
          }
          else if (headersLine0.startsWith("GET ") && userAgent.toUpperCase().indexOf("IPHOTO") < 0)
          {
            //special case where we have to deauth if the client is a .Mac client instead of allowing them in as anonymous
            if (userAgent.toUpperCase().indexOf("ISNETSERVICES") >= 0 || userAgent.toUpperCase().indexOf("DOTMAC") >= 0)
            {
              DEAUTH();
              return;
            }
            //bad dir, DEAUTH
            sendRedirect("/WebInterface/login.html",headers);
            write_command_http("Set-Cookie: referer="+attemptedPath+"; path=/");
            write_command_http("Content-Length: 0");
            write_command_http("");
            return;
          }
        }
        if (headersLine0.startsWith("GET /../")) //WebStatistics user, force login prompt
        {
          thisSession.uiPUT("user_logged_in","false");
        }
      }
      catch(Exception e)
      {
        Common.debug(2, e);
      }
    }

    if ((!thisSession.uiBG("user_logged_in")))
    {
      if (http_len_max > 0) get_raw_http_command((int)http_len_max);
      DEAUTH();
    }
    else //user is logged in
    {
      fixRootDir(domain);//lock them into a directory if we are using virtual domains

      String action = "";
      String http_boundary = "";
      String ifnonematch = "0";
      String move_destination = "";
      String depth = "0";
      boolean headersOnly = false;
      VFS_URL otherFile = null;
      if (!user_dir.toUpperCase().startsWith(thisSession.SG("root_dir").toUpperCase())) user_dir = thisSession.SG("root_dir") + (user_dir.startsWith("/")?user_dir.substring(1):user_dir);
      thisSession.uiPUT("current_dir",user_dir);
      for (int x=0; x<headers.size(); x++)
      {
        data = headers.elementAt(x).toString();
        int endPos = data.lastIndexOf(" HTTP");
        if (endPos < 0) endPos = data.length()-1;

        thisSession.uiPUT("last_logged_command",(data+" ").substring(0,(data+" ").indexOf(" ")));

        if (data.toUpperCase().startsWith("GET ") || data.toUpperCase().startsWith("HEAD "))
        {
          headersOnly = data.toUpperCase().startsWith("HEAD ");
          thisSession.uiPUT("current_dir",data.substring(data.indexOf(" ")+1, endPos));
          if (!thisSession.uiSG("current_dir").toUpperCase().startsWith(thisSession.SG("root_dir").toUpperCase())) thisSession.uiPUT("current_dir",thisSession.SG("root_dir") + (thisSession.uiSG("current_dir").startsWith("/")?thisSession.uiSG("current_dir").substring(1):thisSession.uiSG("current_dir")));
          if (thisSession.uiSG("current_dir").indexOf("\\") >= 0) thisSession.uiPUT("current_dir",thisSession.uiSG("current_dir").replace('\\','/'));
          if (!thisSession.uiSG("current_dir").startsWith("/")) thisSession.uiPUT("current_dir","/"+thisSession.uiSG("current_dir"));

          if (thisSession.uiSG("current_dir").endsWith("/"))
          {
            action = "serve dir";
            if (!thisSession.check_access_privs(thisSession.uiSG("current_dir"), "LIST") || !Common.filter_check("U", Common.last(thisSession.uiSG("current_dir")), server_status_frame.SG("filename_filters_str")))
              action = "serve empty dir";
          }
          else
          {
            action = "serve file";
            boolean ok = thisSession.check_access_privs(thisSession.uiSG("current_dir"), "RETR") && Common.filter_check("U", Common.last(thisSession.uiSG("current_dir")), server_status_frame.SG("filename_filters_str"));
            try
            {
              Properties item = thisSession.uVFS.get_item(thisSession.uiSG("current_dir"));
              //this is a dir item, they must be missing the "/"
              if (item != null && item.getProperty("type","").equals("DIR") && !thisSession.uiSG("current_dir").endsWith("/"))
              {
                sendRedirect(thisSession.uiSG("current_dir")+"/",headers);
                write_command_http("Content-Length: 0");
                write_command_http("");
                return;
              }
              if (okotherFile = new VFS_URL(item,thisSession.uVFS);

              if (otherFile == null && thisSession.uiSG("current_dir").toUpperCase().endsWith(".ZIP"))
              {
                thisSession.uiPUT("current_dir",thisSession.uiSG("current_dir").substring(0,thisSession.uiSG("current_dir").length()-4));
                ok = thisSession.check_access_privs(thisSession.uiSG("current_dir"), "RETR") && Common.filter_check("U", Common.last(thisSession.uiSG("current_dir")), server_status_frame.SG("filename_filters_str"));
                item = thisSession.uVFS.get_item(thisSession.uiSG("current_dir"));
                if (ok)
                {
                  otherFile = new VFS_URL(item,thisSession.uVFS);
                  otherFile = new VFS_URL(otherFile.getParent().getPath()+otherFile.getName()+".zip",thisSession.uVFS);
                }
                else
                {
                  thisSession.uiPUT("current_dir",thisSession.uiSG("current_dir")+".zip");
                }
              }
            }
            catch(Exception e)
            {
              Common.debug(1,e);
            }
          }

          if (data.toUpperCase().startsWith("GET /WEBINTERFACE/"))
          {
            thisSession.uiPUT("macbinary_enabled","false");
            action = "serve file";
            String theFile = data.substring(data.indexOf(" ")+1,endPos);
            theFile = Common.url_decode(theFile);
            theFile = Common.replace_str(theFile,"..","");
            theFile = Common.replace_str(theFile,"\\","/");
            theFile = Common.replace_str(theFile,"//","/");

            otherFile = new VFS_URL(new File(System.getProperty("crushftp.web")+"WebInterface/"+theFile).toURL().toExternalForm(),thisSession.uVFS);
            if (theFile.toUpperCase().startsWith("/WEBINTERFACE/") || theFile.toUpperCase().startsWith(thisSession.SG("root_dir").toUpperCase()+"WEBINTERFACE/"))
            {
              if (!theFile.toUpperCase().endsWith(".JAR")) cacheHeader = "Expires: " + lastModifiedSDF.format(new Date(new Date().getTime()+(1000*60*60*24*1)))+"";

              if (theFile.indexOf("/WebInterface/images/CrushImagePreview/") >= 0)
              {
                //translate first to the users VFS file
                theFile = thisSession.uiSG("current_dir");
                theFile = Common.replace_str(theFile,"/WebInterface/images/CrushImagePreview","");
                String originalTheFile = theFile;
                theFile = theFile.substring(0,theFile.lastIndexOf("."));
                thisSession.uiPUT("current_dir",theFile);
                Properties item = thisSession.uVFS.get_item(thisSession.uiSG("current_dir"));
                if (item != null)
                {
                  otherFile = new VFS_URL(item,thisSession.uVFS);
                  //then get the real local path
                  String destPath = otherFile.getFile().getCanonicalPath();
                  if (destPath.indexOf(":") >= 0) destPath = destPath.substring(destPath.indexOf(":")+1);
                  destPath = destPath.replace('\\','/')+originalTheFile.substring(originalTheFile.lastIndexOf("."));
                  otherFile = new VFS_URL(new File(System.getProperty("crushftp.web")+"WebInterface/images/CrushImagePreview"+destPath).toURL().toExternalForm(),thisSession.uVFS);
                }
              }
              else otherFile = new VFS_URL(new File(System.getProperty("crushftp.web")+"WebInterface/"+theFile.substring("/webInterface/".length())).toURL().toExternalForm(),thisSession.uVFS);
            }

            thisSession.user = new Properties();
          }
        }
        else if (data.toUpperCase().startsWith("POST "))
        {
          thisSession.uiPUT("current_dir",data.substring(data.indexOf(" ")+1, endPos));
          if (!thisSession.uiSG("current_dir").toUpperCase().startsWith(thisSession.SG("root_dir").toUpperCase())) thisSession.uiPUT("current_dir",thisSession.SG("root_dir") + (thisSession.uiSG("current_dir").startsWith("/")?thisSession.uiSG("current_dir").substring(1):thisSession.uiSG("current_dir")));
          if (thisSession.uiSG("current_dir").indexOf("\\") >= 0) thisSession.uiPUT("current_dir",thisSession.uiSG("current_dir").replace('\\','/'));
          if (!thisSession.uiSG("current_dir").startsWith("/")) thisSession.uiPUT("current_dir","/"+thisSession.uiSG("current_dir"));
          if (!thisSession.uiSG("current_dir").endsWith("/")) thisSession.uiPUT("current_dir",thisSession.uiSG("current_dir")+"/");

          action = "process post";
        }
        //webdav commands
        else if (data.toUpperCase().startsWith("LOCK ") || data.toUpperCase().startsWith("UNLOCK ") || data.toUpperCase().startsWith("DELETE ") || data.toUpperCase().startsWith("MKCOL ") || data.toUpperCase().startsWith("PROPFIND ") || data.toUpperCase().startsWith("PUT ") || data.toUpperCase().startsWith("MOVE ") || data.toUpperCase().startsWith("PROPPATCH ") || data.toUpperCase().startsWith("DMMKPATH "|| data.toUpperCase().startsWith("DMMKPATHS ") || data.toUpperCase().startsWith("ACL ") || data.toUpperCase().startsWith("COPY "))
        {
          thisSession.uiPUT("current_dir",data.substring(data.indexOf(" ")+1, endPos));
          if (!thisSession.uiSG("current_dir").toUpperCase().startsWith(thisSession.SG("root_dir").toUpperCase())) thisSession.uiPUT("current_dir",thisSession.SG("root_dir") + (thisSession.uiSG("current_dir").startsWith("/")?thisSession.uiSG("current_dir").substring(1):thisSession.uiSG("current_dir")));
          if (thisSession.uiSG("current_dir").indexOf("\\") >= 0) thisSession.uiPUT("current_dir",thisSession.uiSG("current_dir").replace('\\','/'));
          if (!thisSession.uiSG("current_dir").startsWith("/")) thisSession.uiPUT("current_dir","/"+thisSession.uiSG("current_dir"));

          action = data.toLowerCase().substring(0,data.indexOf(" "));
        }
        else if (data.toUpperCase().startsWith("RANGE: BYTES="))//resuming transfers
        {
          /*
          The first 300 bytes:Range: bytes=0-299
          The second 300 bytes:Range: bytes=300-599
          The last 300 bytes:Range: bytes=-300
          Several ranges : bytes 0-299, bytes=500-900, bytes 1000-
          The entire file from specified location (2341):Range: bytes=2341-
          */
          String amount = data.toUpperCase().substring("RANGE: ".length()) + ",";
          StringTokenizer st = new StringTokenizer(amount,",");
          Vector byteRanges = new Vector();
          thisSession.uiPUT("byteRanges",byteRanges);
          while(st.hasMoreElements())
          {
            String amountStart = st.nextElement().toString().trim();
            amountStart = amountStart.substring(amountStart.toUpperCase().indexOf("=")+1).trim();
            String amountEnd = amountStart.substring(amountStart.indexOf("-")+1).trim();
            amountStart = amountStart.substring(0,amountStart.indexOf("-")).trim();

            if (amountStart.equals(""))amountStart = "0";
            Properties p = new Properties();
            p.put("start", amountStart);
            p.put("end", amountEnd);
            byteRanges.addElement(p);
            if (byteRanges.size() == 1) thisSession.uiPUT("start_resume_loc",amountStart);
          }
        }
        else if (data.toUpperCase().indexOf("BOUNDARY=") >= 0)
        {
          http_boundary = data.substring(data.toUpperCase().indexOf("BOUNDARY=") + "BOUNDARY=".length()).trim();
        }
        else if (data.toUpperCase().indexOf("X-WEBDAV-METHOD:") >= 0 && data.toUpperCase().indexOf("DMMKPATH") >= 0)
        {
          action = data.substring(data.indexOf(" ")).trim().toLowerCase();
        }
        else if (data.toUpperCase().indexOf("X-WEBDAV-METHOD:") >= 0 && data.toUpperCase().indexOf("DMOVERLAY") >= 0)
        {
          action = data.substring(data.indexOf(" ")).trim().toLowerCase();
        }
        else if (data.toUpperCase().indexOf("X-WEBDAV-METHOD:") >= 0 && data.toUpperCase().indexOf("SETPROCESS") >= 0)
        {
          action = data.substring(data.indexOf(" ")).trim().toLowerCase();
        }
        else if (data.toUpperCase().indexOf("X-WEBDAV-METHOD:") >= 0 && data.toUpperCase().indexOf("ACL") >= 0)
        {
          action = data.substring(data.indexOf(" ")).trim().toLowerCase();
        }
        else if (data.toUpperCase().startsWith("IF-MODIFIED-SINCE: "))
        {
          ifnonematch = data.substring(data.toUpperCase().indexOf("IF-MODIFIED-SINCE:") + "IF-MODIFIED-SINCE:".length()).trim();
          try{ifnonematch = lastModifiedSDF.parse(ifnonematch).getTime() + "";}catch(Exception e){}
        }
        else if (data.toUpperCase().startsWith("IF-NONE-MATCH: "))
        {
          ifnonematch = data.substring(data.toUpperCase().indexOf("IF-NONE-MATCH:") + "IF-NONE-MATCH:".length()).trim();
        }
        else if (data.toUpperCase().startsWith("DEPTH: "))
        {
          try{depth = data.substring(data.toUpperCase().indexOf("DEPTH:") + "DEPTH:".length()).trim();}catch(Exception e){}
        }
        else if (data.toUpperCase().startsWith("DESTINATION: ") || data.toUpperCase().startsWith("X-TARGET-HREF:"))
        {
          move_destination = data.substring(data.toUpperCase().indexOf(" ")).trim();
        }
      }
      String initial_current_dir = thisSession.uiSG("current_dir");
      String error_message = "";
      if (action.equals("propfind"))
      {
        String xml = get_raw_http_command((int)http_len_max);
//System.out.println("PROPFIND REQUEST:"+initial_current_dir+"\r\n"+xml);
thisSession.uiVG("user_log").addElement(xml);

        Properties commandActions = new Properties();
        Vector commandActionsOrder = new Vector();
        if (!xml.trim().equals(""))
        {
          try
          {
            Document doc = sax.build(new StringReader(xml));
            List items = doc.getRootElement().getChildren();
            Iterator i = items.iterator();
            if (i.hasNext())
            {
              Element element = (Element)i.next();
              List items2 = element.getChildren();
              Iterator i2 = items2.iterator();
              while (i2.hasNext())
              {
                Element element2 = (Element)i2.next();
                String key = element2.getName();
                String val = element2.getText();
                commandActions.put(key,val);
                commandActionsOrder.addElement(key);
              }
            }
          }
          catch(Throwable e)
          {
            Common.debug(1,e);
          }
        }

        xml = doPropFind(commandActions,depth,false, commandActionsOrder);
        if (SG("username").equals("anonymous"))
        {
          Properties item = thisSession.uVFS.get_item(initial_current_dir);
          if (item.getProperty("privs").indexOf("(view)") < 0)
          {
            //deauth user...probably looking for public iDisk
            DEAUTH();
            return;
          }
        }
        if (xml != null)
        {
          write_command_http("HTTP/1.1 207 Multi-Status");
          write_standard_headers();
          write_command_http("Content-Length: "+(xml.getBytes("UTF8").length+2));
          write_command_http("Content-Type: text/xml; charset=utf-8");
          String dir = initial_current_dir;
          if (dir.startsWith(thisSession.SG("root_dir"))) dir = initial_current_dir.substring(thisSession.SG("root_dir").length()-1);
          Properties item = thisSession.uVFS.get_item(initial_current_dir);
          if (item != null && item.getProperty("type","").equalsIgnoreCase("DIR") && !dir.endsWith("/"))
          {
            write_command_http("Content-Location: " + Common.url_encode(dir,"/")+"/");
          }

          write_command_http("");
          write_command_raw(xml+"\r\n");
//System.out.println("PROPFIND RESPONSE:("+depth+")"+xml);
thisSession.uiVG("user_log").addElement(xml);
        }
        else
        {
          String msg = "Not Found: Resource does not exist";
          write_command_http("HTTP/1.1 404 Not Found: Resource does not exist");
          done = true;
          write_standard_headers();
          write_command_http("Content-Type: text/xml; charset=utf-8");
          write_command_http("Content-Length: "+msg.length());
          write_command_http("");
          write_command_raw(msg);
        }
      }
      else if (action.equals("proppatch"))
      {
/*
<?xml version="1.0" encoding="utf-8" ?>
<a:propertyupdate xmlns:a="DAV:" xmlns:b="http://www.apple.com/SyncServices">
<a:set><a:prop><b:dataclassname>com.apple.MailAccounts</b:dataclassname></a:prop></a:set>
<a:set><a:prop><b:displayname>Mail Accounts</b:displayname></a:prop></a:set>
</a:propertyupdate>
*/
        String xml = get_raw_http_command((int)http_len_max);
//System.out.println("PROPPATCH REQUEST:"+thisSession.uiSG("current_dir")+"\r\n"+xml);
thisSession.uiVG("user_log").addElement(xml);
        Properties commandActions = new Properties();
        Vector commandActionsOrder = new Vector();
        try
        {
          Document doc = sax.build(new StringReader(xml));
          List items = doc.getRootElement().getChildren();
          Iterator i = items.iterator();
          while (i.hasNext())
          {
            Element element = (Element)i.next();
            List items2 = element.getChildren();
            Iterator i2 = items2.iterator();
            while (i2.hasNext())
            {
              Element element2 = (Element)i2.next();
              List items3 = element2.getChildren();
              Iterator i3 = items3.iterator();
              while (i3.hasNext())
              {
                Element element4 = (Element)i3.next();
                String key = element4.getName();
                String val = element4.getText();
                commandActions.put(key,val);
                commandActionsOrder.addElement(key);
              }
            }
          }
        }
        catch(Exception e)
        {
          Common.debug(1,e);
        }

        Properties item = thisSession.uVFS.get_item(thisSession.uiSG("current_dir"));

        Properties commandActions2 = (Properties)proppatches.get(new VFS_URL(item,thisSession.uVFS).getFile().getCanonicalPath());
        if (!new VFS_URL(item,thisSession.uVFS).getFile().exists()) commandActions2 = null;
        if (commandActions2 == null) commandActions2 = new Properties();
        commandActions2.putAll(commandActions);

        proppatches.put(new VFS_URL(item,thisSession.uVFS).getFile().getCanonicalPath(),commandActions2);

        savePropPatches();
        xml = doPropFind(commandActions,depth,true,commandActionsOrder);
        if (xml != null)
        {
          write_command_http("HTTP/1.1 207 Multi-Status");
          String dir = initial_current_dir;
          if (dir.startsWith(thisSession.SG("root_dir"))) dir = initial_current_dir.substring(thisSession.SG("root_dir").length()-1);
          item = thisSession.uVFS.get_item(initial_current_dir);
          if (item != null && item.getProperty("type","").equalsIgnoreCase("DIR") && !dir.endsWith("/"))
          {
            write_command_http("Content-Location: " + Common.url_encode(dir,"/")+"/");
          }
          write_standard_headers();
          write_command_http("Content-Length: "+(xml.getBytes("UTF8").length+2));
          write_command_http("Content-Type: text/xml;charset=utf-8");
          write_command_http("");
          write_command_raw(xml+"\r\n");
//System.out.println("PROPPATCH RESPONSE:("+depth+")"+xml);
thisSession.uiVG("user_log").addElement(xml);
        }
        else
        {
          String msg = "Not Found: Resource does not exist";
          write_command_http("HTTP/1.1 404 Not Found: Resource does not exist");
          write_standard_headers();
          write_command_http("Content-Type: text/xml;charset=utf-8");
          write_command_http("Content-Length: "+msg.length());
          write_command_http("");
          write_command_raw(msg);
        }
      }
      else if (action.equals("delete"))
      {
        String dir = initial_current_dir;
        if (dir.startsWith(thisSession.SG("root_dir"))) dir = initial_current_dir.substring(thisSession.SG("root_dir").length()-1);
        Properties item = thisSession.uVFS.get_item(initial_current_dir);

        Enumeration keys = proppatches.keys();
        try
        {
          String propPath = new VFS_URL(item,thisSession.uVFS).getFile().getCanonicalPath();
          while(keys.hasMoreElements())
          {
            String key = keys.nextElement().toString();
            if (key.startsWith(propPath)) proppatches.remove(key);
          }
          savePropPatches();
        }
        catch(Exception e)
        {

        }

        thisSession.uiPUT("the_command","DELE");
        thisSession.uiPUT("the_command_data",thisSession.uiSG("current_dir"));
        error_message += thisSession.do_DELE(true);
        thisSession.uVFS.reset();


        if (error_message.length() == 0) write_command_http("HTTP/1.1 204  No Content");
        else write_command_http("HTTP/1.1 401  Access Denied.");

        if (item != null && item.getProperty("type","").equalsIgnoreCase("DIR") && !dir.endsWith("/"))
        {
          write_command_http("Content-Location: " + Common.url_encode(dir,"/")+"/");
        }
        if (item != null && item.getProperty("type","").equalsIgnoreCase("DIR"))
        {
          //NotMac hack
          //if an attempt is made to delete the schema items folder, honor it, but then re-create the folder immediately afterwords or else the sync fails.  WHY?
          if (thisSession.uiSG("current_dir").toUpperCase().indexOf("/LIBRARY/APPLICATION SUPPORT/SYNCSERVICES/SCHEMAS/") >= 0)
          {
            thisSession.do_MKD(true);
            thisSession.uVFS.reset();
          }
        }

        write_standard_headers();
        write_command_http("Content-Length: 0");
        write_command_http("");
      }
      else if (action.equals("acl"))
      {
        String xml = get_raw_http_command((int)http_len_max);

        String dir = initial_current_dir;
        if (dir.startsWith(thisSession.SG("root_dir"))) dir = initial_current_dir.substring(thisSession.SG("root_dir").length()-1);
        Properties item = thisSession.uVFS.get_item(initial_current_dir);

        write_command_http("HTTP/1.1 200 OK");

        write_standard_headers();
        write_command_http("Content-Length: 0");
        write_command_http("");
      }
      else if (action.equals("copy"))
      {
        thisSession.uVFS.reset();
        thisSession.uiPUT("the_command_data",thisSession.uiSG("current_dir"));

        String from = thisSession.uiSG("current_dir");
        //verify read access
        boolean ok = true;
        if (thisSession.check_access_privs(thisSession.uiSG("current_dir"), "RETR"))
        {
          thisSession.uiPUT("current_dir",new URL(move_destination).getPath());
          if (!thisSession.uiSG("current_dir").toUpperCase().startsWith(thisSession.SG("root_dir").toUpperCase())) thisSession.uiPUT("current_dir",thisSession.SG("root_dir") + (thisSession.uiSG("current_dir").startsWith("/")?thisSession.uiSG("current_dir").substring(1):thisSession.uiSG("current_dir")));
          if (thisSession.uiSG("current_dir").indexOf("\\") >= 0) thisSession.uiPUT("current_dir",thisSession.uiSG("current_dir").replace('\\','/'));
          if (!thisSession.uiSG("current_dir").startsWith("/")) thisSession.uiPUT("current_dir","/"+thisSession.uiSG("current_dir"));
          thisSession.uiPUT("the_command_data",thisSession.uiSG("current_dir"));
        }
        else ok = false;
        if (ok && thisSession.check_access_privs(thisSession.uiSG("current_dir"), "STOR"))
        {
          String to = thisSession.uiSG("current_dir");
          Properties source = thisSession.uVFS.get_item(from);
          Properties dest = thisSession.uVFS.get_item_parent(to);
          RandomAccessFile in = new RandomAccessFile(new VFS_URL(source,thisSession.uVFS).getFile().getCanonicalPath(),"r");
          RandomAccessFile out = new RandomAccessFile(new VFS_URL(dest,thisSession.uVFS).getFile().getCanonicalPath(),"rw");
          byte b[] = new byte[32768];
          int bytesRead = 0;
          while(bytesRead >= 0)
          {
            bytesRead = in.read(b);
            if (bytesRead >= 0) out.write(b,0,bytesRead);
          }
          in.close();
          out.close();

          thisSession.uVFS.reset();
        }
        if (ok) write_command_http("HTTP/1.1 204  No Content");
        else write_command_http("HTTP/1.1 403  Access Denied.");

        write_standard_headers();
        write_command_http("Content-Length: 0");
        write_command_http("");
        //verify they passed in a token to use this file
      }
      else if (action.equals("setprocess"))
      {
        String accountInfo = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><methodResponse><params><param><value>success</value></param></params></methodResponse>";

        write_command_http("HTTP/1.1 200 OK");
        write_command_http("Pragma: no-cache");
        write_standard_headers();
        write_command_http("Content-Length: "+accountInfo.length());
        write_command_http("Content-Type: text/xml");
        write_command_http("");
        write_command_raw(accountInfo);thisSession.add_log(accountInfo, "ACCEPT");
        return;
      }
      else if (action.equals("dmmkpath") || action.equals("dmmkpaths"))
      {
        String the_dir = thisSession.uiSG("current_dir");
        if (!the_dir.endsWith("/")) the_dir += "/";

        Properties item = null;
        Vector reversePath = new Vector();
        while(item == null && !the_dir.equals(""))
        {
          item = thisSession.uVFS.get_item(the_dir);
          if (item == null)
          {
            reversePath.addElement(the_dir);
            the_dir = Common.all_but_last(the_dir);
          }
        }
        if (item.getProperty("privs").indexOf("(makedir)") >= 0)
        {
          //make the dirs for them
          new VFS_URL(thisSession.uiSG("current_dir"),thisSession.uVFS).mkdirs();

          String xml = get_raw_http_command((int)http_len_max);
//System.out.println("DMMKPATH:"+thisSession.uiSG("current_dir")+"\r\n"+xml);
thisSession.uiVG("user_log").addElement(xml);
          try
          {
            Document doc = sax.build(new StringReader(xml));
            Element root = doc.getRootElement();
            List instructions = root.getContent();
            item = thisSession.uVFS.get_item(thisSession.uiSG("current_dir"));
            String basePath = Common.all_but_last(new VFS_URL(item,thisSession.uVFS).getFile().getCanonicalPath());
            for (int x=0; x<instructions.size(); x++)
            {
              Element inst = (Element)instructions.get(x);
              String path = Common.url_decode(((Element)inst.getContent().get(1)).getText());
              new VFS_URL(basePath+path.substring(1),thisSession.uVFS).mkdirs();
            }
          }
          catch(Exception e)
          {

          }

        }
        thisSession.uVFS.reset();

        if (error_message.length() == 0 || error_message.indexOf(LOC.G("exists")) >= 0)
        {
          Element root = new Element("multistatus","DAV:");
          Document doc = new Document(root);
          Element response = new Element("response","DAV:");
          root.addContent(response);
          Element href = new Element("href","DAV:");
          response.addContent(href);
          href.setText(the_dir);
          Element status = new Element("status","DAV:");
          response.addContent(status);
          status.setText("HTTP/1.1 201 Created");

          if (xmlOut == null)
          {
              xmlOut = new XMLOutputter();
              Format f = Format.getPrettyFormat();
              f.setExpandEmptyElements(false);
              //f.setIndent("\t");
              xmlOut.setFormat(f);
          }
          String xml= xmlOut.outputString(doc);

          write_command_http("HTTP/1.1 207 Multi-Status");
          write_standard_headers();
          write_command_http("Content-Length: "+(xml.getBytes("UTF8").length+2));
          write_command_http("Content-Type: text/xml;charset=utf-8");
          write_command_http("");
          write_command_raw(xml+"\r\n");
//  System.out.println("DMMKPATH RESPONSE:"+xml);
  thisSession.uiVG("user_log").addElement(xml);
          thisSession.uVFS.reset();
        }
        else
        {
          write_command_http("HTTP/1.1 403  Access Denied.");
          write_standard_headers();
          write_command_http("Content-Length: 0");
          write_command_http("");
        }
      }
      else if (action.equals("mkcol"))
      {
        thisSession.uiPUT("the_command","MKDIR");
        String the_dir = thisSession.uiSG("current_dir");
        if (!the_dir.endsWith("/")) the_dir += "/";
        thisSession.uiPUT("the_command_data",the_dir);
        error_message += thisSession.do_MKD(false);
        thisSession.uVFS.reset();
        boolean good = false;
        if (error_message.length() == 0 || error_message.indexOf(LOC.G("exists")) >= 0)
        {
          good = true;
          Properties item = thisSession.uVFS.get_item(thisSession.uiSG("current_dir")+"/");
          thisSession.accessExceptions.put(thisSession.uiSG("current_dir")+"/",item);
          write_command_http("HTTP/1.1 201 Created");
          for (int x=0; x<headers.size(); x++)
          {
            data = headers.elementAt(x).toString();
            if (data.startsWith("Last-Modified: "))
            {
              String modified = data.substring(data.indexOf(":")+1).trim();
              thisSession.uiPUT("the_command","MDTM");
              SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
              thisSession.uiPUT("the_command_data",thisSession.uiSG("current_dir")+" "+sdf.format(sdf_rfc1123.parse(modified)));
              error_message += thisSession.do_MDTM();
            }
          }
          thisSession.uVFS.reset();
        }
        else write_command_http("HTTP/1.1 403  Access Denied.");
        write_standard_headers();
        if (good) write_command_http("Content-Location: " + Common.url_encode(the_dir,"/"));
        write_command_http("Content-Length: 16"); //without this line, iWeb hangs indefinitely
        write_command_http("");
        write_command_http("Resource created"); //without this line, iWeb hangs indefinitely
      }
      else if (action.equals("lock"))
      {
        String xml = get_raw_http_command((int)http_len_max);
//System.out.println("LOCK REQUEST:"+thisSession.uiSG("current_dir")+"\r\n"+xml);
thisSession.uiVG("user_log").addElement(xml);

        Element root = new Element("prop","D","DAV:");
        Document doc = new Document(root);
        Element lockdiscovery = new Element("lockdiscovery","D", "DAV:");
        root.addContent(lockdiscovery);
        Element activelock = new Element("activelock","D", "DAV:");
        lockdiscovery.addContent(activelock);
        Element locktype = new Element("locktype","D", "DAV:");
        activelock.addContent(locktype);
        Element write = new Element("write","D", "DAV:");
        locktype.addContent(write);
        Element lockscope = new Element("lockscope","D", "DAV:");
        activelock.addContent(lockscope);
        Element exclusive = new Element("exclusive","D", "DAV:");
        lockscope.addContent(exclusive);
        Element depthElement = new Element("depth","D", "DAV:");
        activelock.addContent(depthElement);
        depthElement.setText(depth);

        Element owner = new Element("owner","D", "DAV:");
        activelock.addContent(owner);
        Element href = new Element("href","D", "DAV:");
        owner.addContent(href);

        Element synclockinfo = new Element("synclockinfo","SY", "http://www.apple.com/SyncServices");
        href.addContent(synclockinfo);

        Element lock_user = new Element("lock-user","SY", "SY:");
        synclockinfo.addContent(lock_user);
        lock_user.setText(SG("username"));
        if (xml.indexOf("clientid>") >= 0)
        {
          Element clientid = new Element("clientid","SY", "SY:");
          synclockinfo.addContent(clientid);
          clientid.setText(xml.substring(xml.indexOf("clientid>")+9,xml.indexOf("<",xml.indexOf("clientid>"))));
        }
        if (xml.indexOf("clientname>") >= 0)
        {
          Element clientname = new Element("clientname","SY", "SY:");
          synclockinfo.addContent(clientname);
          clientname.setText(xml.substring(xml.indexOf("clientname>")+11,xml.indexOf("<",xml.indexOf("clientname>"))));
        }
        Element acquiredate = new Element("acquiredate","SY", "SY:");
        synclockinfo.addContent(acquiredate);
        SimpleDateFormat lockSDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
        acquiredate.setText(lockSDF.format(new Date()));

        Element timeout = new Element("timeout","D", "DAV:");
        activelock.addContent(timeout);
        timeout.setText("Second-239");

        Properties lock = new Properties();
        lock.put("token", (ServerSessionNotMacXML.makeGuid("",3)+"-"+ServerSessionNotMacXML.makeGuid("",7)+"-"+ServerSessionNotMacXML.makeGuid("",3)+"-"+ServerSessionNotMacXML.makeGuid("",10)+"-"+ServerSessionNotMacXML.makeGuid("",9)).toLowerCase());
        lock.put("stamp", new Date().getTime()+"");
        lock.put("duration", "600");
        Properties item = thisSession.uVFS.get_item(initial_current_dir);
        try{lock.put("resource", new VFS_URL(item,thisSession.uVFS).getFile().getCanonicalPath().toUpperCase());}catch(Exception e){}
        locktokens.put(lock.getProperty("token"), lock);

        Element locktoken = new Element("locktoken","D", "DAV:");
        activelock.addContent(locktoken);
        Element href2 = new Element("href","D", "DAV:");
        locktoken.addContent(href2);
        href2.setText("dotmaclocktoken:"+lock.getProperty("token"));

        if (xmlOut == null)
        {
            xmlOut = new XMLOutputter();
            Format f = Format.getPrettyFormat();
            f.setExpandEmptyElements(false);
            //f.setIndent("\t");
            xmlOut.setFormat(f);
        }
        xml= xmlOut.outputString(doc);

        write_command_http("HTTP/1.1 200 OK");
        write_standard_headers();
        write_command_http("Content-Length: "+(xml.getBytes("UTF8").length+2));
        write_command_http("Content-Type: text/xml;charset=utf-8");
        write_command_http("Lock-Token: <dotmaclocktoken:"+lock.getProperty("token")+">");
        String dir = initial_current_dir;
        if (dir.startsWith(thisSession.SG("root_dir"))) dir = initial_current_dir.substring(thisSession.SG("root_dir").length()-1);
        item = thisSession.uVFS.get_item(initial_current_dir);
        if (item != null && item.getProperty("type","").equalsIgnoreCase("DIR") && !dir.endsWith("/"))
        {
          write_command_http("Content-Location: " + Common.url_encode(dir,"/")+"/");
        }
        write_command_http("");
        write_command_raw(xml+"\r\n");
//System.out.println("LOCK RESPONSE:"+xml);
thisSession.uiVG("user_log").addElement(xml);
      }
      else if (action.equals("unlock"))
      {
        write_command_http("HTTP/1.1 204 No Content");
        write_standard_headers();
        write_command_http("Content-Length: 0");
        write_command_http("");
        //verify they passed in the token to unlock it
        Properties lock = new Properties();
        lock.put("token", new Date().getTime()+"");
        lock.put("stamp", new Date().getTime()+"");
        lock.put("duration", "600");
        Properties item = thisSession.uVFS.get_item(initial_current_dir);
        lock.put("resource", new VFS_URL(item,thisSession.uVFS).getFile().getCanonicalPath().toUpperCase());
        locktokens.put(lock.getProperty("token"), lock);
      }
      else if (action.equals("put"))
      {
        boolean ok = doPutFile(http_len_max,done);
        if (ok)
        {
          write_command_http("HTTP/1.1 201  Created");
          write_command_http("Last-Modified: " + lastModifiedSDF.format(new Date()));
          for (int x=0; x<headers.size(); x++)
          {
            data = headers.elementAt(x).toString();
            if (data.startsWith("Last-Modified: "))
            {
              String modified = data.substring(data.indexOf(":")+1).trim();
              thisSession.uiPUT("the_command","MDTM");
              SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
              thisSession.uiPUT("the_command_data",thisSession.uiSG("current_dir")+" "+sdf.format(sdf_rfc1123.parse(modified)));
              error_message += thisSession.do_MDTM();
            }
          }
          thisSession.uVFS.reset();

          //NotMac hacks :(  //special things Apple's servers seem to be doing in the background
          if (thisSession.uiSG("current_dir").indexOf("/Web/Sites/iPhoto/") >= 0 && thisSession.uiSG("current_dir").endsWith("index.rss"))
          {
            //modify file replacing www.mac.com with our server address
            Properties item = thisSession.uVFS.get_item(thisSession.uiSG("current_dir"));

            RandomAccessFile f = new RandomAccessFile("/Library/Application Support/NotMac/url.txt","r");
            byte b[] = new byte[(int)f.length()];
            f.readFully(b);
            String url = new String(b);
            f.close();
            url = url.substring(url.indexOf("//"+2,url.lastIndexOf("/")));

            f = new RandomAccessFile(new VFS_URL(item,thisSession.uVFS).getFile().getCanonicalPath(),"rw");
            b = new byte[(int)f.length()];
            f.readFully(b);
            String s = new String(b);
            s = Common.replace_str(s,"web.mac.com",url);
            f.setLength(0);
            f.write(s.getBytes());
            f.close();
          }
          else if (thisSession.uiSG("current_dir").indexOf("/.calendars/") >= 0 && thisSession.uiSG("current_dir").endsWith(".ics") && userAgent.indexOf("iCal") >= 0)
          {
            //add a virtual reference to this calendar to "anonymous"'s account.
            String calendarName = Common.last(thisSession.uiSG("current_dir"));
            Properties calendars = new Properties();
            calendars.put("url","FILE:/"+new File("/Library/Application Support/NotMac/Storage/"+thisSession.uiSG("user_name")+"/Sites/.calendars/"+calendarName).getCanonicalPath());
            calendars.put("type","dir");
            Vector v = new Vector();
            v.addElement(calendars);
            common_code.writeXMLObject("/Library/Application Support/NotMac/CrushFTP/users/127.0.0.1_53818/anonymous/VFS/"+thisSession.uiSG("user_name")+"/"+calendarName,v,"VFS");
          }
        }
        else write_command_http("HTTP/1.1 403  Access Denied.");

        write_standard_headers();
        write_command_http("Content-Length: 0");
        write_command_http("");
        //verify they passed in a token to use this file
      }
      else if (action.equals("move") || action.equals("dmoverlay"))
      {
        thisSession.uVFS.reset();
        String rename_from = thisSession.uiSG("current_dir");
        thisSession.uiPUT("the_command_data",rename_from);
        error_message += thisSession.do_RNFR();
        thisSession.uiPUT("current_dir",move_destination);
        try{thisSession.uiPUT("current_dir",new URL(move_destination).getPath());}catch(Exception e){Common.debug(2,e);}
        if (!thisSession.uiSG("current_dir").toUpperCase().startsWith(thisSession.SG("root_dir").toUpperCase())) thisSession.uiPUT("current_dir",thisSession.SG("root_dir") + (thisSession.uiSG("current_dir").startsWith("/")?thisSession.uiSG("current_dir").substring(1):thisSession.uiSG("current_dir")));
        if (thisSession.uiSG("current_dir").indexOf("\\") >= 0) thisSession.uiPUT("current_dir",thisSession.uiSG("current_dir").replace('\\','/'));
        if (!thisSession.uiSG("current_dir").startsWith("/")) thisSession.uiPUT("current_dir","/"+thisSession.uiSG("current_dir"));
        thisSession.uiPUT("the_command_data",thisSession.uiSG("current_dir"));
        if (error_message.length() == 0)
        {
          if (action.equals("dmoverlay")) //notMac hack...we have to copy overtop the existing directory, not just rename
          {
            thisSession.uiPUT("the_command","RNTO");
            thisSession.uiPUT("last_logged_command","RNTO");
            String the_dir = thisSession.fixupDir();
            Properties item = thisSession.uVFS.get_item_parent(the_dir);
            if (thisSession.check_access_privs(the_dir, thisSession.uiSG("the_command"), item) && Common.filter_check("R", Common.last(the_dir), server_status_frame.SG("filename_filters_str")))
            {
              Properties item_src = thisSession.uVFS.get_item_or_vitem(rename_from);
              VFS_URL v_src = new VFS_URL(item_src,thisSession.uVFS);
              VFS_URL v_dest = new VFS_URL(item,thisSession.uVFS);
              Common.recurseCopy(v_src.getFile().getCanonicalPath()+"/",v_dest.getFile().getCanonicalPath()+"/");
              Common.recurseDelete(v_src.getFile().getCanonicalPath()+"/",false);
            }
            else
            {
              error_message += "Access denied";
            }
          }
          else error_message += thisSession.do_RNTO(true);
        }
        thisSession.uVFS.reset();
        if (error_message.length() == 0) write_command_http("HTTP/1.1 204  No Content");
        else if (error_message.indexOf("RNFR") >= 0) write_command_http("HTTP/1.1 404  Not Found");
        else write_command_http("HTTP/1.1 403  Access Denied.");

        write_standard_headers();
        write_command_http("Content-Length: 0");
        write_command_http("");
        //verify they passed in a token to use this file
      }
      else if (action.equals("process post"))// post item...so get the items and do the action
      {
        if (thisSession.uiSG("current_dir").equals(thisSession.SG("root_dir") + "StartCrushFTPAdminSession.bin/") && headers.elementAt(0).toString().startsWith("POST ") && thisSession.SG("site").indexOf("(CONNECT)") >= 0)
        {
          write_command_http("HTTP/1.1 200 OK");
          write_command_http("Pragma: no-cache");
          write_command_http("Connection: close");
          write_standard_headers();
          write_command_http("");
          thisSession.data_sock = sock;
          thisSession.uiPUT("current_user",thisSession.uiSG("user_name"));
          thisSession.do_remote_admin_input(original_is);
          sock = null;
          original_os = null;
          original_is = null;
          done = true;
          return;
        }
        Vector items = new Vector();
        boolean skip_refresh = false;
        if (!http_boundary.equals("")) items = get_http_post_items(http_boundary,http_len_max);
        else
        {
          if (thisSession.uiSG("current_dir").toUpperCase().endsWith(".PDF") || thisSession.uiSG("current_dir").toUpperCase().endsWith(".FDF"))
          {
            boolean ok = doPutFile(http_len_max, done);
            String redirectPDF = thisSession.uiSG("current_dir");
            if (redirectPDF.endsWith("/")) redirectPDF = redirectPDF.substring(0,redirectPDF.length()-1);
            redirectPDF = Common.last(redirectPDF);

            String ext = redirectPDF.substring(redirectPDF.indexOf("."));
            String base = redirectPDF.substring(0,redirectPDF.indexOf("."));
            if (ext.equalsIgnoreCase(".FDF")) ext = ".PDF";
            if (ok) sendRedirect("/WebInterface/"+base+"Success"+ext,headers);
            else write_command_http("HTTP/1.1 403  Access Denied.");
            write_command_http("Connection: close");
            write_command_http("");
            kill_all = true;
            done = true;
            thisSession.uVFS = null;
            return;
          }
          else if (thisSession.uiSG("current_dir").equals(thisSession.SG("root_dir") + "servlet/f1.xml.ServiceRequestV3/") && headers.elementAt(0).toString().startsWith("POST "))
          {
            ssnmx.process(headers,this);
            return;
          }
          else
          {
            if (http_len_max < 1024*10000)//max post is 10MB
            {
              String xml = get_raw_http_command((int)http_len_max);
//              System.out.println(xml);
              thisSession.add_log(xml, "ACCEPT");

              if (thisSession.uiSG("current_dir").endsWith("/WebObjects/Info.woa/wa/XMLRPC/accountInfo/")) //iWeb publishing does this
              {
                if (xml.indexOf("daysLeftUntilExpiration") >= 0) //checks the days until account expires
                {
                  xml = "<?xml version='1.0'?>\r\n"+
                   "<methodResponse><params><param><value><struct><member><name>daysLeftUntilExpiration</name>\r\n"+
                   "<value><int>59</int></value></member></struct></value></param></params></methodResponse>\r\n";
                }
                else if (xml.indexOf("servicesAvailable") >= 0) //may also check the services that are available
                {
                  xml = "<?xml version='1.0'?><methodResponse><params><param><value><struct><member><name>servicesAvailable</name>"+
                     "<value><array><value><string>iDisk</string></value><value><string>iSync</string></value><value><string>Email</string></value>"+
                     "<value><string>WebHosting</string></value><value><string>Backup</string></value><value><string>BTMM</string></value></array></value></member></struct></value></param></params></methodResponse>\r\n";
                }

                write_command_http("HTTP/1.1 200 OK");
                write_command_http("Pragma: no-cache");
                write_standard_headers();
                write_command_http("Content-Length: "+xml.length());
                write_command_http("Content-Type: text/html");
                write_command_http("");
                write_command_raw(xml);thisSession.add_log(xml, "ACCEPT");
                return;
              }
              else if (thisSession.uiSG("current_dir").endsWith("dotMacPreferencesPaneMessage/"))
              {
                String username = changeUser(xml);
                boolean ok = username != null;
                if (!ok) username = "anonymous";

                RandomAccessFile in = new RandomAccessFile("/Library/Application Support/NotMac/dotMacPreferencesPaneMessage.html","r");
                byte b[] = new byte[(int)in.length()];
                in.readFully(b);
                in.close();
                String html = new String(b).replace('\"', '\'');

                in = new RandomAccessFile("/Library/Application Support/NotMac/url.txt","r");
                b = new byte[(int)in.length()];
                in.readFully(b);
                in.close();
                String url = new String(b).replace('\"', '\'');

                html = Common.replace_str(html,"%url%",url);
                if (username.equals("anonymous")) html = Common.replace_str(html,"%username%","");
                else html = Common.replace_str(html,"%username%",username+"/");


                String welcome = "{ \r"+
                "  messageHTML = \""+html+"\"; \r"+
                "  service = dotMacPreferencesPaneMessage; \r"+
                "  servicesAvailable = (iDisk, iSync, Email, WebHosting, BTMM, Backup); \r"+
                "  statusCode = success; \r"+
                "  version = 1; \r"+
                "}";
                if (!ok)
                {
                  //see if they have the cookie crushauth.
                  //if not, this is the first attempt, so respond OK so the page is loaded
                  //if the do, say their password is wrong.
                  boolean foundCookie = false;
                  for (int x=0; x<headers.size(); x++) //first loop through and see if they have a cookie for auth
                  {
                    data = headers.elementAt(x).toString();
                    if (data.startsWith("Cookie: "))
                    {
                      if (data.indexOf("CrushAuth=") >= 0) foundCookie = true;
                    }
                  }
                  if (foundCookie)
                  {
                    welcome = "{ \r"+
                    "messageHTML = \""+html+"\"; \r"+
                    "  service = dotMacPreferencesPaneMessage; \r"+
                    "   forgottenPasswordURL = \"http://www.notmacchallenge.com/\"; \r"+
                    "  servicesAvailable = (iDisk, iSync, Email, WebHosting, BTMM, Backup); \r"+
                    "   statusCode = authorizationFailed; \r"+
                    "}";
                  }

                  write_command_http("HTTP/1.1 401 OK");
                }
                else write_command_http("HTTP/1.1 200 OK");

                welcome = Common.replace_str(welcome,"%status%","Welcome to NotMac!");

                write_command_http("Pragma: no-cache");
                write_standard_headers();
                write_command_http("Content-Length: "+welcome.length());
                write_command_http("Content-Type: text/html");
                write_command_http("");
                write_command_raw(welcome);thisSession.add_log(welcome, "ACCEPT");
                return;
              }
              else if (thisSession.uiSG("current_dir").endsWith("/WebObjects/Info.woa/wa/Query/configureDisk/") || thisSession.uiSG("current_dir").endsWith("retrieveDiskConfiguration/"))
              {
                String username = changeUser(xml);
                boolean ok = username != null;
                if (!ok)
                {
                  DEAUTH();
                  return;
                }

                long quota = -12345;
                long total_quota = -12345;
                try{quota=thisSession.get_quota_used("/"+username+"/");}catch(Exception e){}
                try{total_quota=thisSession.get_total_quota("/"+username+"/");}catch(Exception e){}
                if (quota == -12345) quota = 0;
                if (total_quota == -12345) total_quota = 300*1024*1024;

                //get the current privs on this dir to see if its read or write for the user named "public"
                Properties permissions = (Properties)Common.readXMLObject("/Library/Application Support/NotMac/CrushFTP/users/127.0.0.1_53818/public/VFS.XML");
                if (xml.indexOf("guestWriteEnabled = Y") >= 0 || xml.indexOf("guestWriteEnabled = 1") >= 0)
                {
                  if (thisSession.uiSG("current_dir").endsWith("/WebObjects/Info.woa/wa/Query/configureDisk/"))
                  {
                    permissions.put(("/"+username+"/Public/").toUpperCase(),"(read)(write)(view)(resume)");
                  }
                }
                else if (thisSession.uiSG("current_dir").endsWith("/WebObjects/Info.woa/wa/Query/configureDisk/"))
                {
                  permissions.put(("/"+username+"/Public/").toUpperCase(),"(read)(view)(resume)");
                }
                try{common_code.writeXMLObject("/Library/Application Support/NotMac/CrushFTP/users/127.0.0.1_53818/public/VFS.XML",permissions,"VFS");}catch(Exception ee){}

                boolean guestWriteEnabled = permissions.getProperty(("/"+username+"/Public/").toUpperCase(),"").indexOf("(write)") >= 0;

                if (xml.indexOf("generalPassword = ") >= 0 && thisSession.uiSG("current_dir").endsWith("/WebObjects/Info.woa/wa/Query/configureDisk/"))
                {
                  String pass = xml.substring(xml.indexOf("generalPassword = ")+"generalPassword = ".length(),xml.indexOf(";",xml.indexOf("generalPassword = "))).trim();
                  publicpasswords.put(("/"+username+"/Public/").toUpperCase(),common_code.encode_pass(pass,"DES"));
                  savePublicPasswords();
                }
                else if (thisSession.uiSG("current_dir").endsWith("/WebObjects/Info.woa/wa/Query/configureDisk/"))
                {
                  publicpasswords.remove(("/"+username+"/Public/").toUpperCase());
                  savePublicPasswords();
                }

                boolean hasGeneralPassword = publicpasswords.containsKey(("/"+username+"/Public/").toUpperCase());

                String idiskConfig = "{ \r"+
                   "  payload = {\r"+
                   "  authenticatedReadEnabled = "+(hasGeneralPassword&&!guestWriteEnabled?"Y":"N")+";\r"+
                   "  authenticatedWriteEnabled = "+(hasGeneralPassword&&guestWriteEnabled?"Y":"N")+";\r"+
                   "  guestReadEnabled = Y;\r"+
                   "  guestWriteEnabled = "+(guestWriteEnabled?"Y":"N")+";\r"+
                   "  hasGeneralPassword = "+(hasGeneralPassword?"Y":"N")+";\r";
                if (thisSession.uiSG("current_dir").endsWith("retrieveDiskConfiguration/"))
                {
                   idiskConfig += "  iDiskQuotaInBytes = "+(total_quota)+";\r"+
                   "  iDiskUsedBytes = "+quota+";\r";
                }
                idiskConfig += "  relativePath = Public;\r"+
                   "}; \r"+
                   "statusCode = success;\r"+
                   "}";
                write_command_http("HTTP/1.1 200 OK");
                write_command_http("Pragma: no-cache");
                write_standard_headers();
                write_command_http("Content-Length: "+idiskConfig.length());
                write_command_http("Content-Type: text/html");
                write_command_http("");
                write_command_raw(idiskConfig);thisSession.add_log(idiskConfig, "ACCEPT");
                return;
              }
              else if (thisSession.uiSG("current_dir").endsWith("/WebObjects/RequestRouter.woa/wa/HomePagePublishing/accountInfo/"))
              {
                Document doc2 = sax.build(new StringReader(xml));
//System.out.println("REQUEST:"+xmlOut.outputString(doc2));
                Element root = doc2.getRootElement();
                Element dict = root.getChild("dict").getChild("dict");
                String fakeStr = "username = "+((Element)dict.getChildren("string").get(0)).getText()+"; \r password = "+((Element)dict.getChildren("string").get(1)).getText()+";";
                String username = changeUser(fakeStr);
                boolean ok = username != null;
                if (!ok)
                {
                  DEAUTH();return;
                }

                long quota = -12345;
                long total_quota = -12345;
                try{quota=thisSession.get_quota_used("/"+username+"/");}catch(Exception e){}
                try{total_quota=thisSession.get_total_quota("/"+username+"/");}catch(Exception e){}
                if (quota == -12345) quota = 0;
                if (total_quota == -12345) total_quota = 300*1024*1024;

                xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"+
                "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\r\n"+
                "<plist version=\"1.0\">\r\n"+
                "<dict>\r\n"+
                "<key>iDiskFreeBytes</key>\r\n"+
                "<string>"+(total_quota-quota)+"</string>\r\n"+
                "<key>sites</key>\r\n"+
                "<array>\r\n"+
                "<string>"+SG("username")+"</string>\r\n"+
                "</array>\r\n"+
                "<key>success</key>\r\n"+
                "<string>yes</string>\r\n"+
                "</dict>\r\n"+
                "</plist>\r\n";

                write_command_http("HTTP/1.1 200 OK");
                write_command_http("Pragma: no-cache");
                write_standard_headers();
                write_command_http("Content-Length: "+xml.length());
                write_command_http("Content-Type: text/html");
                write_command_http("");
                write_command_raw(xml);thisSession.add_log(xml, "ACCEPT");
                return;
              }
              else if (thisSession.uiSG("current_dir").endsWith("/WebObjects/Info.woa/wa/Query/accountInfo/"))
              {
                String accountInfo = "{payload = {}; statusCode = success; }";

                write_command_http("HTTP/1.1 200 OK");
                write_command_http("Pragma: no-cache");
                write_standard_headers();
                write_command_http("Content-Length: "+accountInfo.length());
                write_command_http("Content-Type: text/html");
                write_command_http("");
                write_command_raw(accountInfo);
                return;
              }
              else if (thisSession.uiSG("current_dir").endsWith("accountInfo/"))
              {
                String accountInfo = "<?xml version='1.0'?> \r"+
                   "<methodResponse><params><param><value><struct> \r"+
                   "<member><name>daysLeftUntilExpiration</name><value><int>-1</int></value></member> \r"+
                   "</struct></value></param></params></methodResponse> \r";

                write_command_http("HTTP/1.1 200 OK");
                write_command_http("Pragma: no-cache");
                write_standard_headers();
                write_command_http("Content-Length: "+accountInfo.length());
                write_command_http("Content-Type: text/html");
                write_command_http("");
                write_command_raw(accountInfo);thisSession.add_log(accountInfo, "ACCEPT");
                return;
              }
              else if (thisSession.uiSG("current_dir").indexOf("/.Temporary Web Resources/") >= 0 && thisSession.uiSG("current_dir").endsWith("/Site/"))
              {
                String accountInfo = "";

                thisSession.uiPUT("the_command","MKDIR");
                String the_dir = thisSession.uiSG("current_dir");
                if (!the_dir.endsWith("/")) the_dir += "/";
                thisSession.uiPUT("the_command_data",the_dir);
                error_message += thisSession.do_MKD(true);
                thisSession.uVFS.reset();

                write_command_http("HTTP/1.1 200 OK");
                write_command_http("Pragma: no-cache");
                write_standard_headers();
                write_command_http("Content-Length: "+accountInfo.length());
                write_command_http("Content-Type: text/html");
                write_command_http("");
                write_command_raw(accountInfo);thisSession.add_log(accountInfo, "ACCEPT");
                return;
              }
              else if (thisSession.uiSG("current_dir").endsWith("/subscribe/") || thisSession.uiSG("current_dir").endsWith("/notify/"))
              {
                String unixTime = (new Date().getTime()/1000) + "";
                unixTime = "0";
                String accountInfo = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><methodResponse><params><param><value><struct><member><name>resultCode</name><value>Success</value></member><member><name>timestamp</name><value>"+unixTime+"</value></member><member><name>resultBody</name><value><array><data></data></array></value></member></struct></value></param></params></methodResponse>";

                write_command_http("HTTP/1.1 200 OK");
                write_command_http("Pragma: no-cache");
                write_standard_headers();
                write_command_http("Content-Length: "+accountInfo.length());
                write_command_http("Content-Type: text/xml");
                write_command_http("");
                write_command_raw(accountInfo);thisSession.add_log(accountInfo, "ACCEPT");
                return;
              }
            }
          }
        }
        //do action from command
        Properties p = new Properties();
        for (int x=0; x<items.size(); x++)
        {
          Properties pp = (Properties)items.elementAt(x);
          p.putAll(pp);
        }
        error_message += p.getProperty("stop_message","");
        if (!skip_refresh) skip_refresh = p.getProperty("refresh","true").equalsIgnoreCase("false");
        if (p.getProperty("type","").equals("text"))
        {
//LOGIN
          if (p.getProperty("the_action","").toUpperCase().startsWith("LOGIN"))
          {
            thisSession.uiPUT("current_password",p.getProperty("password"));
            thisSession.uiPUT("user_name",p.getProperty("username"));
            this_thread.setName(thisSession.uiSG("user_name") + ":(" + thisSession.uiSG("user_number") + ")-" + thisSession.uiSG("user_ip") + " (control)");
            thisSession.uVFS = null;
            boolean good = thisSession.login_user_pass();
            if (good)
            {
              thisSession.do_event("Logged In.", "PASS","");
              writeCookieAuth = true;
              try
              {
                String id = thisSession.SG("messageForm");
                if (id != null && id.substring(id.indexOf(":")+1).equals("always"))
                {
                  Properties user_stat = ((Properties)thisSession.user_info.get("stat"));
                  if (user_stat.get("messages") == null) user_stat.put("messages",new Properties());
                  Properties messages = (Properties)user_stat.get("messages");
                  messages.remove(id.substring(0,id.indexOf(":")));
                }
              }
              catch(Exception e)
              {
              }
            }
            if (!skip_refresh)
            {
              if (p.getProperty("referer","/").equals("") || p.getProperty("referer","/").toUpperCase().indexOf("LOGIN.HTML") >= 0) sendRedirect("/",headers);
              else sendRedirect(p.getProperty("referer","/"),headers);
              write_command_http("Set-Cookie: referer=; path=/");
              write_command_http("");
              done = true;
              thisSession.uVFS = null;
              return;
            }
          }
//EMAILPASSWORD
          else if (p.getProperty("the_action","").toUpperCase().startsWith("EMAILPASSWORD"))
          {
            String lookupUsername = p.getProperty("username");
            Properties lookupUser = common_code.read_user(thisSession.uiSG("listen_ip_port"),lookupUsername);
            String result = "";
            if (lookupUser.getProperty("site","").toUpperCase().indexOf("(SITE_EMAILPASSWORD)") >= 0)
            {
              String pass = lookupUser.getProperty("password","");
              if (pass.startsWith("SHA:") || pass.startsWith("CRYPT3:")) pass = LOC.G("(Your password is encrypted and cannot be revealed.  Please contact your server administrator to have it reset.)");
              else pass = common_code.decode_pass(pass);
              String to = lookupUser.getProperty("email","");
              String from = to;
              if (thisSession.server_status_frame.SG("smtp_server").equals(""))
              {
                result = LOC.G("This server is not configured to send email password reminders.");
              }
              else if (!to.equals(""))
              {
                result = common_code.send_mail(thisSession.server_status_frame.SG("discovered_ip"),to,"","", from, LOC.G("CrushFTP Password Reminder"), LOC.G("Your password is : ")+pass+"\r\n\r\n"+LOC.G("Requested from IP:")+thisSession.uiSG("user_ip"), thisSession.server_status_frame.SG("smtp_server"), thisSession.server_status_frame.SG("smtp_user"), thisSession.server_status_frame.SG("smtp_pass"), thisSession.server_status_frame.SG("smtp_ssl").equals("true"));
                thisSession.add_log_formatted(LOC.G("Password Emailed to user:")+lookupUsername+"  "+to+"   "+LOC.G("Email Result:") + result,"POST");
                if (result.toUpperCase().indexOf("ERROR") >= 0) result = LOC.G("An error occured when generating the email.");
                else result = LOC.G("An email was just sent to the email address associated with your username.");
              }
              else
              {
                result = LOC.G("Your username does not have an email specified in its account.");
              }
            }
            else
            {
              result = LOC.G("Your username does not allow you to have your password emailed to you.");
            }
            write_command_http("HTTP/1.1 200 OK");
            write_command_http("Pragma: no-cache");
            write_command_http("Content-Type: text/html;charset=utf-8");
            write_standard_headers();
            write_command_http("Content-Length: "+(result.length()+2));
            write_command_http("");
            write_command_http(result);
            return;
          }
//LOGOUT
          else if (p.getProperty("the_action","").toUpperCase().startsWith("LOGOUT"))
          {
            done = true;
            kill_all = true;
            String sessionid = thisSession.uiSG("CrushAuth");
            globalSessions.remove(thisSession.uiSG("user_ip")+"_"+sessionid+"_user");
            globalSessions.remove(thisSession.uiSG("user_ip")+"_"+sessionid+"_pass");

            sendRedirect("/WebInterface/login.html",headers);
            write_command_http("Connection: close");
            write_command_http("Set-Cookie: CrushAuth=; path=/");
            thisSession.uiPUT("CrushAuth","");
            write_command_http("");
            kill_all = true;
            done = true;
            thisSession.uVFS = null;
            return;
          }
//MESSAGECONFIRM
          else if (p.getProperty("the_action","").toUpperCase().startsWith("MESSAGECONFIRM"))
          {
            String messageId = p.getProperty("MessageFormId","");
            Properties user_stat = ((Properties)thisSession.user_info.get("stat"));
            if (user_stat.get("messages") == null) user_stat.put("messages",new Properties());
            Properties messages = (Properties)user_stat.get("messages");
            if (messageId.length() > 0) messages.put(messageId,p);
            if (!skip_refresh)
            {
              if (p.getProperty("referer","/").equals("")) sendRedirect("/",headers);
              else sendRedirect(p.getProperty("referer","/"),headers);
              write_command_http("Set-Cookie: referer=; path=/");
              write_command_http("Connection: close");
              write_command_http("");
              done = true;
              return;
            }
          }
//REFRESH
          else if (p.getProperty("the_action","").toUpperCase().startsWith("REFRESH"))
          {
            if (!skip_refresh)
            {
              String current_dir = thisSession.uiSG("current_dir");
              if (current_dir.startsWith(thisSession.SG("root_dir"))) current_dir = current_dir.substring(thisSession.SG("root_dir").length());
              if (!current_dir.startsWith("/")) current_dir = "/"+current_dir;
              sendRedirect(current_dir,headers);
              write_command_http("Set-Cookie: referer=; path=/");
              write_command_http("Connection: close");
              write_command_http("");
              done = true;
              return;
            }
          }
//QUICKLIST
          else if (p.getProperty("the_action","").toUpperCase().startsWith("QUICKLIST"))
          {
            //just accept the post and give a quick list
            if (thisSession == null || thisSession.user == null) return;
            String curInterface = thisSession.SG("webInterfaceTemplate");
            thisSession.user.put("webInterfaceTemplate","/WebInterface/quicklist.xsl");
            doServeDir(headersOnly,error_message,null,headers,ifnonematch,true,true);
            thisSession.user.put("webInterfaceTemplate",curInterface);
            return;
          }
//DELE
          else if (p.getProperty("the_action","").toUpperCase().startsWith("DELE "))
          {
            String item_name = p.getProperty("the_action",""); item_name = item_name.substring(item_name.indexOf(" ")+1);
            thisSession.uiPUT("the_command","DELE");

            String itemList[] = item_name.split(":");
            for (int itemLoop=0; itemLoop<itemList.length; itemLoop++)
            {
              if (itemList[itemLoop].length() > 0)
              {
                thisSession.uiPUT("the_command_data",itemList[itemLoop]);
                String msg = thisSession.do_DELE(true);
                error_message += msg.equals("")?"":itemList[itemLoop]+":"+msg;
                thisSession.uVFS.reset();
              }
            }
          }
//MKD
          else if (p.getProperty("the_action","").toUpperCase().startsWith("MKD "))
          {
            String item_name = p.getProperty("the_action",""); item_name = item_name.substring(item_name.indexOf(" ")+1);
            thisSession.uiPUT("the_command","MKD");
            thisSession.uiPUT("the_command_data",item_name.trim());
            error_message += thisSession.do_MKD(false);
            thisSession.uVFS.reset();
          }
//MDTM
          else if (p.getProperty("the_action","").toUpperCase().startsWith("MDTM "))
          {
            String item_data = p.getProperty("the_action",""); item_data = item_data.substring(item_data.indexOf(" ")+1);
            thisSession.uiPUT("the_command","MDTM");
            thisSession.uiPUT("the_command_data",item_data.trim());
            error_message += thisSession.do_MDTM();
            thisSession.uVFS.reset();
          }
//RNFR RNTO
          else if (p.getProperty("the_action","").toUpperCase().startsWith("RNFR "))
          {
            String item_name = p.getProperty("the_action",""); item_name = item_name.substring(item_name.indexOf(" ")+1,item_name.indexOf(":"));
            thisSession.uiPUT("the_command","RNFR");
            thisSession.uiPUT("the_command_data",item_name);
            error_message += thisSession.do_RNFR();
            if (error_message.equals(""))
            {
              String item_name2 = p.getProperty("the_action","");  item_name2 = item_name2.substring(item_name2.indexOf(":RNTO ")+6);
              thisSession.uiPUT("the_command","RNTO");
              thisSession.uiPUT("the_command_data",item_name2);
              if (!item_name.equals(item_name2))
              {
                error_message += thisSession.do_RNTO(false);
                thisSession.uVFS.reset();
              }
            }
          }
//USEROPTIONS
          else if (p.getProperty("the_action","").toUpperCase().equalsIgnoreCase("USEROPTIONS"))
          {
            if (thisSession.SG("site").indexOf("(SITE_PASS)") >= 0)
            {
              String current_password = p.getProperty("current_password","");
              String new_password1 = p.getProperty("new_password1","");
              String new_password2 = p.getProperty("new_password2","");
              if (current_password.length() > 0 && new_password1.length() > 0)
              {
                if (current_password.equals(thisSession.uiSG("current_password")) && new_password1.equals(new_password2) && !thisSession.uiSG("user_name").equalsIgnoreCase("anonymous"))
                {
                  thisSession.do_ChangePass(thisSession.uiSG("user_name"),new_password1);
                  error_message+=LOC.G("Password updated.");
                }
                else if (!current_password.equals(thisSession.uiSG("current_password")))
                {
                  error_message+=LOC.G("You did not enter the correct current password.");
                }
                else if (!new_password1.equals(new_password2))
                {
                  error_message+=LOC.G("You did not enter the same password for verification the second time.");
                }
              }
            }
          }
//SEARCH
          else if (p.getProperty("the_action","").toUpperCase().equalsIgnoreCase("SEARCH"))
          {
            boolean name1 = p.getProperty("name1","").equalsIgnoreCase("on");
            String name1_action = p.getProperty("name1_action","");
            String name1_value = p.getProperty("name1_value","");

            boolean name2 = p.getProperty("name2","").equalsIgnoreCase("on");
            String name2_action = p.getProperty("name2_action","");
            String name2_value = p.getProperty("name2_value","");

            boolean date1 = p.getProperty("date1","").equalsIgnoreCase("on");
            String date1_action = p.getProperty("date1_action","");
            String date1_value = p.getProperty("date1_value","");

            boolean date2 = p.getProperty("date2","").equalsIgnoreCase("on");
            String date2_action = p.getProperty("date2_action","");
            String date2_value = p.getProperty("date2_value","");

            boolean size1 = p.getProperty("size1","").equalsIgnoreCase("on");
            String size1_action = p.getProperty("size1_action","");
            String size1_value = p.getProperty("size1_value","");

            boolean type1 = p.getProperty("type1","").equalsIgnoreCase("on");
            String type1_action = p.getProperty("type1_action","");

            boolean meta1 = p.getProperty("meta1","").equalsIgnoreCase("on");
            String meta1_value = p.getProperty("meta1_value","");
            Vector metas = new Vector();
            if (meta1) metas = thisSession.server_status_frame.getMetchingMetas(meta1_value,thisSession.server_item);

            thisSession.uiPUT("the_command","LIST");
            thisSession.uiPUT("the_command_data",name1);


            Vector listing = new Vector();
            Properties status = new Properties();
            class Lister implements Runnable
            {
              Vector listing = null;
              Properties status = null;
              public Lister(Vector listing, Properties status)
              {
                this.listing = listing;
                this.status = status;
              }
              public void run()
              {
                status.put("done","false");
                try{thisSession.uVFS.getListing(listing,thisSession.uiSG("current_dir"),20,1000,false,true);}catch(Exception e){}
                status.put("done","true");
              }
            }
            new Thread(new Lister(listing,status)).start();
            Vector foundItems = new Vector();
            SimpleDateFormat mmddyyyy = new SimpleDateFormat("MM/dd/yyyy");
            while (listing.size() == 0) Thread.sleep(100);
            long processedCount = 0;
            while (status.getProperty("done","false").equalsIgnoreCase("false") || listing.size() > 0)
            {
              while(status.getProperty("done","false").equalsIgnoreCase("false") && listing.size() == 0) Thread.sleep(100);
              if (listing.size() == 0) break;
              Properties pp = (Properties)listing.elementAt(0);
              listing.removeElementAt(0);
              processedCount++;
              System.getProperties().put("crushftp.activeSearch.info"+thisSession.uiSG("CrushAuth"),"Searched "+processedCount+" items.");
              try
              {
                if (pp.getProperty("privs","").indexOf("(read)") < 0 || pp.getProperty("privs","").indexOf("(invisible)") >= 0 || pp.getProperty("privs","").indexOf("(view)") < 0)
                {
                  //hidden item
                }
                else
                {
                  boolean name_ok = true;
                  boolean date_ok = true;
                  boolean size_ok = true;
                  boolean type_ok = true;
                  boolean meta_ok = true;
                  if (name1)
                  {
                    if (name1_action.equalsIgnoreCase("contains") && pp.getProperty("name").toUpperCase().indexOf(name1_value.toUpperCase()) < 0) name_ok = false;
                    if (name1_action.equalsIgnoreCase("starts with") && !pp.getProperty("name").toUpperCase().startsWith(name1_value.toUpperCase())) name_ok = false;
                    if (name1_action.equalsIgnoreCase("ends with") && !pp.getProperty("name").toUpperCase().endsWith(name1_value.toUpperCase())) name_ok = false;
                  }
                  if (name2)
                  {
                    if (name2_action.equalsIgnoreCase("contains") && pp.getProperty("name").toUpperCase().indexOf(name2_value.toUpperCase()) < 0) name_ok = false;
                    if (name2_action.equalsIgnoreCase("starts with") && !pp.getProperty("name").toUpperCase().startsWith(name2_value.toUpperCase())) name_ok = false;
                    if (name2_action.equalsIgnoreCase("ends with") && !pp.getProperty("name").toUpperCase().endsWith(name2_value.toUpperCase())) name_ok = false;
                  }

                  if (date1)
                  {
                    long modified1 = Long.parseLong(pp.getProperty("modified"));
                    long modified2 = mmddyyyy.parse(date1_value).getTime();
                    if (date1_action.equalsIgnoreCase("before") && modified2 <= modified1) date_ok = false;
                    else if (date1_action.equalsIgnoreCase("after") && modified2 >= modified1) date_ok = false;
                  }
                  if (date2)
                  {
                    long modified1 = Long.parseLong(pp.getProperty("modified"));
                    long modified2 = mmddyyyy.parse(date2_value).getTime();
                    if (date2_action.equalsIgnoreCase("before") && modified2 <= modified1) date_ok = false;
                    else if (date2_action.equalsIgnoreCase("after") && modified2 >= modified1) date_ok = false;
                  }
                  if (size1)
                  {
                    long file_size1 = Long.parseLong(pp.getProperty("size"));
                    long file_size2 = Long.parseLong(size1_value)*1024;//kilobytes
                    if (size1_action.equalsIgnoreCase("bigger than") && file_size2 >= file_size1) size_ok = false;
                    else if (size1_action.equalsIgnoreCase("smaller than") && file_size2 <= file_size1) size_ok = false;
                  }
                  if (type1)
                  {
                    String item_type1 = pp.getProperty("type");
                    if (type1_action.equalsIgnoreCase("file") && !item_type1.equalsIgnoreCase("file")) type_ok = false;
                    else if (type1_action.equalsIgnoreCase("folder") && !item_type1.equalsIgnoreCase("dir")) type_ok = false;
                  }
                  if (meta1)
                  {
                    meta_ok = false;
                    for (int x=0; x<metas.size(); x++)
                    {
                      Properties meta_item = (Properties)metas.elementAt(x);
                      if (meta_item.getProperty("url","").toUpperCase().equals(pp.getProperty("url").toUpperCase()))
                      {
                        pp.put("metaInfo",meta_item.get("metaInfo"));
                        meta_ok = true;
                      }
                    }
                  }

                  if (name_ok && date_ok && size_ok && type_ok && meta_ok)
                  {
                    foundItems.addElement(pp);
                    String privs = pp.getProperty("privs","");
                    if (privs.indexOf("(comment") >= 0)
                    {
                      privs = privs.substring(0,privs.indexOf("(comment"))+privs.substring(privs.indexOf(")",privs.indexOf("(comment")));
                    }
                    privs = Common.replace_str(privs,"(inherited)","");
                    String current_dir2 = pp.getProperty("root_dir");
                    if (current_dir2.toUpperCase().startsWith(thisSession.SG("root_dir").toUpperCase())) current_dir2 = current_dir2.substring(thisSession.SG("root_dir").length()-1);
                    pp.put("privs",privs + "(comment"+Common.url_encode(LOC.G("Containing Folder")+":<a href='"+current_dir2+"'>"+current_dir2+"</a>")+")");
                  }
                }
              }
              catch(Exception e)
              {
                Common.debug(1,e);
              }
            }
            System.getProperties().remove("crushftp.activeSearch.info"+thisSession.uiSG("CrushAuth"));
            doServeDir(headersOnly,error_message,foundItems,headers,ifnonematch,true,false);
          }
//SIZE -- used in Browser upload to get status of upload
          else if (p.getProperty("the_action","").toUpperCase().startsWith("SIZE"))
          {
            write_command_http("HTTP/1.1 200 OK");
            write_command_http("Pragma: no-cache");
            write_command_http("Content-Type: text/html;charset=utf-8");
            write_standard_headers();
            //thisSession.uiSG("current_dir");
            String sizeInfo = "";
            if (!System.getProperties().getProperty("crushftp.activeUpload.info"+thisSession.uiSG("CrushAuth"),"").equals(""))
            {
              sizeInfo = System.getProperties().getProperty("crushftp.activeUpload.info"+thisSession.uiSG("CrushAuth"),"");
            }
            write_command_http("Content-Length: "+(sizeInfo.length()+2));
            write_command_http("");
            write_command_http(sizeInfo);
            return;
          }
//SEARCHPROGRESS -- used in Browser upload to get status of upload
          else if (p.getProperty("the_action","").toUpperCase().startsWith("SEARCHPROGRESS"))
          {
            write_command_http("HTTP/1.1 200 OK");
            write_command_http("Pragma: no-cache");
            write_command_http("Content-Type: text/html;charset=utf-8");
            write_standard_headers();
            //thisSession.uiSG("current_dir");
            String searchInfo = "";
            if (!System.getProperties().getProperty("crushftp.activeSearch.info"+thisSession.uiSG("CrushAuth"),"").equals(""))
            {
              searchInfo = System.getProperties().getProperty("crushftp.activeSearch.info"+thisSession.uiSG("CrushAuth"),"");
            }
            write_command_http("Content-Length: "+(searchInfo.length()+2));
            write_command_http("");
            write_command_http(searchInfo);
            return;
          }
//.ZIP
          else if (p.getProperty("the_action","").toUpperCase().startsWith("ZIP "))
          {
            write_command_http("HTTP/1.1 200 OK");
            int validSecs = 30;
            write_command_http("Cache-Control: post-check="+validSecs+",pre-check="+(validSecs*10));
            //write_command_http("Pragma: no-cache"); not allowed or IE 6 can't download in HTTPS
            write_command_http("Content-Type: application/zip");
            write_standard_headers();

            String item_name = p.getProperty("the_action",""); item_name = item_name.substring(item_name.indexOf(" ")+1);
            thisSession.uiPUT("the_command","RETR");

            String itemList[] = item_name.split(":");
            String current_dir = thisSession.uiSG("current_dir");
            Properties item = thisSession.uVFS.get_item(thisSession.uiSG("current_dir"));
            if(item == null) item = new Properties();
            int max = itemList.length;
            if (max > 100) max = 100;//prevent DOS by only allowing 100 threads max to be started.
            for (int itemLoop=0; itemLoop<max; itemLoop++)
            {
              if (itemList[itemLoop].length() > 0)
              {
                String current_dir2 = itemList[itemLoop];
                if (!current_dir2.toUpperCase().startsWith(thisSession.SG("root_dir"))) current_dir2 = thisSession.SG("root_dir") + current_dir2.substring(1);
                thisSession.uiPUT("current_dir",current_dir2);
                if (thisSession.check_access_privs(thisSession.uiSG("current_dir"), "RETR"))
                {
                  common_code.startMultiThreadZipper(thisSession.uVFS, retr,thisSession.uiSG("current_dir"),0);
                }
              }
            }
            Thread.sleep(2000);//give time for zipping threads to start
            otherFile = new VFS_URL(item,thisSession.uVFS);

            thisSession.uiPUT("current_dir",current_dir);
            String fname = "archive.zip";
            if (itemList.length == 1) fname = itemList[0]+".zip";
            if (p.getProperty("item1","").length() > 0) fname = p.getProperty("item1","");
            write_command_http("Content-Disposition: attachment; filename=\""+fname+"\"");
            write_command_http("Connection: close");
            write_command_http("");
            done = true;
            thisSession.uiPUT("file_transfer_mode","BINARY");
            retr.data_os = original_os;
            retr.httpDownload = true;

            String the_dir = thisSession.uiSG("current_dir");
            //allow a plugin to alter the logged file name in case it may have altered the incoming the_command_data
            Properties pp = new Properties();
            pp.put("the_dir",the_dir);
            thisSession.runPlugin("transfer_path", pp);
            the_dir = pp.getProperty("the_dir",the_dir);

            retr.init_vars(the_dir, thisSession.uiLG("start_resume_loc"), -1, thisSession, item, false, "", otherFile);
            retr.runOnce = true;
            retr.run();

            return;
          }
        }
        //if a file wasn't uploaded, refresh dir.
        for (int x=0; x<items.size(); x++)
        {
          Properties pp = (Properties)items.elementAt(x);
          if (pp.getProperty("type","").equals("file"))
          {
            skip_refresh = true;
          }
        }
        error_message += p.getProperty("callback","");
        if (skip_refresh)
        {
          String s = error_message;
          if (s.length() == 0) s = "~~~OK~~~";
          write_command_http("HTTP/1.1 200 OK");
          write_command_http("Pragma: no-cache");
          write_standard_headers();
          write_command_http("Content-Type: text/html;charset=utf-8");
          write_command_http("Content-Length: "+write_command_http_size(s));
          write_command_http("");
          write_command_http(s);
        }
        else doServeDir(headersOnly,error_message, null,headers,ifnonematch,false,false);
      }
      else if (action.equals("serve dir") || action.equals("serve empty dir"))
      {
        doServeDir(headersOnly,error_message,null,headers,ifnonematch,false,false);
      }
      else if (action.equals("serve file"))
      {
        doServeFile(otherFile, headers, ifnonematch, headersOnly, forceFileName);
      }
    }
  }//end handle_http_requests

  public void doServeFile(VFS_URL otherFile, Vector headers, String ifnonematch, boolean headersOnly, boolean forceFileName) throws Exception
  {
    if (thisSession.uiSG("current_dir").indexOf("webdav-method=TRUTHGET") >= 0)
    {
      otherFile = new VFS_URL("file:///Library/Application Support/NotMac/truthget.txt",null);
    }
    if (otherFile == null)
    {
      if (thisSession.uiSG("current_dir").equals(thisSession.SG("root_dir") + "StartCrushFTPAdminSession.bin") && headers.elementAt(0).toString().startsWith("GET ") && thisSession.SG("site").indexOf("(CONNECT)") >= 0)
      {
        write_command_http("HTTP/1.1 200 OK");
        write_command_http("Pragma: no-cache");
        write_standard_headers();
        write_command_http("Connection: close");
        write_command_http("");
        thisSession.data_sock = sock;
        thisSession.uiPUT("current_user",thisSession.uiSG("user_name"));
        thisSession.do_remote_admin_output();
        sock = null;
        original_os = null;
        original_is = null;
        done = true;
        return;
      }
      else
      {
        boolean ok1 = thisSession.check_access_privs(Common.all_but_last(thisSession.uiSG("current_dir")), "RETR") && Common.filter_check("U", Common.last(thisSession.uiSG("current_dir")), server_status_frame.SG("filename_filters_str"));
        boolean ok2 = thisSession.check_access_privs(thisSession.uiSG("current_dir"), "RETR") && Common.filter_check("U", Common.last(thisSession.uiSG("current_dir")), server_status_frame.SG("filename_filters_str"));
        if (ok1 || ok2) write_command_http("HTTP/1.1 404 Not Found");
        else write_command_http("HTTP/1.1 403 Access Denied.");
        write_command_http("Content-Length: 0");
        write_command_http("");
      }
    }
    else
    {
      updateMimes();
      String ext = "";
      if (otherFile.toString().lastIndexOf(".") >= 0) ext = otherFile.toString().substring(otherFile.toString().lastIndexOf(".")).toUpperCase();
      if (mimes.getProperty(ext,"").equals("")) ext = "*";

      Properties item = thisSession.uVFS.get_item(thisSession.uiSG("current_dir"));
      if(item == null) item = new Properties();

      String htmlData = "";
      if ((mimes.getProperty(ext,"").toUpperCase().endsWith("/HTML") || mimes.getProperty(ext,"").toUpperCase().endsWith("/X-JAVA-JNLP-FILE")) && (otherFile.toString().indexOf("/WebInterface/") >= 0 || thisSession.uiSG("current_dir").toUpperCase().startsWith("/WEBINTERFACE/") || thisSession.BG("WebServerSSI")))
      {
        String current_dir = thisSession.uiSG("current_dir");
        if (current_dir.startsWith(thisSession.SG("root_dir"))) current_dir = current_dir.substring(thisSession.SG("root_dir").length());
        if (!current_dir.startsWith("/")) current_dir = "/"+current_dir;
        VFS_URL url = otherFile;
        url.getInputStream();
        byte b[] = new byte[bufferSize];
        htmlData = "";
        int bytesRead = 0;
        while (bytesRead >= 0)
        {
          bytesRead = url.read(b);
          if (bytesRead > 0) htmlData += new String(b,0,bytesRead);
        }
        url.close();
        if (otherFile.getName().equalsIgnoreCase("login.html"))
        {
          if (!server_status_frame.SG("default_logo").equals("") && !server_status_frame.SG("default_logo").equalsIgnoreCase("logo.gif"))
          {
            htmlData = Common.replace_str(htmlData,"logo.gif",server_status_frame.SG("default_logo"));
          }
        }
        else if (otherFile.getName().equalsIgnoreCase("crushftp.jnlp"))
        {
          htmlData = server_status_frame.change_vars_to_values(htmlData,thisSession);
          htmlData = Common.replace_str(htmlData, "%base_url%", getBaseUrl(headers));
        }
        else if (otherFile.getName().toUpperCase().endsWith(".EXIF"))
        {
          Common.debug(2,otherFile.getFile().toURL().toString());
          htmlData = common_code.readXMLDocumentAndConvert(otherFile.getFile().toURL(),"/WebInterface/exif.xsl");
          if (htmlData == null) htmlData = "";
        }
        if (thisSession.BG("WebServerSSI"))
        {
          int depth = 0;
          while (htmlData.toUpperCase().indexOf("<!--#INCLUDE") >= 0)
          {
            int loc = htmlData.toUpperCase().indexOf("<!--#INCLUDE");
            int loc2 = htmlData.indexOf("\"",loc)+1;
            String importFilename = htmlData.substring(loc2,htmlData.indexOf("\"",loc2+2));
            Properties importItem = null;
            if (importFilename.startsWith("/"))
            {
              if (!importFilename.startsWith(thisSession.SG("root_dir"))) importFilename = thisSession.SG("root_dir") + importFilename.substring(1);
              importItem = thisSession.uVFS.get_item(importFilename);
            }
            else
            {
              String the_dir = current_dir;
              if (!the_dir.endsWith("/")) the_dir = Common.all_but_last(the_dir);
              importFilename = the_dir+importFilename;
              if (!importFilename.startsWith(thisSession.SG("root_dir"))) importFilename = thisSession.SG("root_dir") + importFilename.substring(1);
              importItem = thisSession.uVFS.get_item(importFilename);
            }
            String importHtml = "";
            if (importItem != null)
            {
              VFS_URL importUrl = new VFS_URL(importItem,thisSession.uVFS);
              importUrl.getInputStream();
              bytesRead = 0;
              while (bytesRead >= 0)
              {
                bytesRead = importUrl.read(b);
                if (bytesRead > 0) importHtml += new String(b,0,bytesRead);
              }
              importUrl.close();
            }
            String replacer = htmlData.substring(loc,htmlData.indexOf("-->",loc)+3);
            htmlData = Common.replace_str(htmlData,replacer,importHtml);

            if (depth++ > 100) break;
          }
        }
      }
      long checkDate = new Date().getTime();
      try{checkDate = Long.parseLong(ifnonematch);}catch(Exception e){}

      boolean checkOK = false;
      if(checkDate > 0 && checkDate >= otherFile.getLastModified() && !headersOnly) checkOK = true;
      else if(checkDate > 0 && !headersOnly)//test for offset of exact match by a 24 hour range
      {
        checkDate -= 1000*60*60*24;//negative 24 hours first
        for (int x=0; x<=48; x++)
        {
          if(checkDate == otherFile.getLastModified()){checkOK = true;break;}
          checkDate += (1000*60*60);//1 hour
        }
      }
      if(checkOK)
      {
        int validSecs = 30;
        if (otherFile.getPath().toUpperCase().indexOf("/WEBINTERFACE/") >= 0 || thisSession.BG("WebServerMode"))
        {
          if (otherFile.getName().toUpperCase().endsWith(".GIF") || otherFile.getName().toUpperCase().endsWith(".PNG") || otherFile.getName().toUpperCase().endsWith(".JPG") || otherFile.getName().toUpperCase().endsWith(".CSS") || otherFile.getName().toUpperCase().endsWith(".XSL") || otherFile.getName().toUpperCase().endsWith(".JS") || otherFile.getName().toUpperCase().endsWith(".ICO") || otherFile.getName().toUpperCase().endsWith(".HTML"))
          {
            validSecs = 3000;
          }
        }
        write_command_http("HTTP/1.1 304 Not Modified");
        write_standard_headers();
        write_command_http("Cache-Control: post-check="+validSecs+",pre-check="+(validSecs*10));
        if (cacheHeader.length() > 0){write_command_http(cacheHeader);cacheHeader = "";}
        write_command_http("Last-Modified: " + lastModifiedSDF.format(new Date(otherFile.getLastModified())));
        write_command_http("ETag: "+otherFile.getLastModified()+"");
        write_command_http("Content-Length: 0");
        write_command_http("");
      }
      else
      {
        Vector byteRanges = thisSession.uiVG("byteRanges");
        if (byteRanges.size() > 0 && htmlData.length() == 0) write_command_http("HTTP/1.1 206 Partial Content");
        else write_command_http("HTTP/1.1 200 OK");
        write_standard_headers();
        String byteRangeBoundary = Common.makeBoundary();
        String contentType = mimes.getProperty(ext,"");
        if (byteRanges.size() <= 1) write_command_http("Content-Type: " + contentType);
        else if (byteRanges.size() > 1) write_command_http("Content-Type: multipart/byteranges; boundary="+byteRangeBoundary);

        if (cacheHeader.length() > 0){write_command_http(cacheHeader);cacheHeader = "";}
        write_command_http("Last-Modified: " + lastModifiedSDF.format(new Date(otherFile.getLastModified())));
        write_command_http("ETag: "+otherFile.getLastModified()+"");
        if (headersOnly) //don't cache header info since we might be using ajax to check progress
        {
          write_command_http("Pragma: no-cache"); //this is not allowed or IE 6 will not save files when using HTTPS
        }
        boolean quickWrite = false;
        if (htmlData.length() > 0) quickWrite = true;

        //populate the real size of the file when none was specified in the byte range header
        String amountEnd = otherFile.length()+"";
        for (int x=0; x<byteRanges.size(); x++)
        {
          Properties p = (Properties)byteRanges.elementAt(x);
          if (p.getProperty("end","").equals("")) p.put("end",amountEnd);
        }

        if (!otherFile.exists() && otherFile.getName().toUpperCase().endsWith(".ZIP"))
        {
          common_code.startMultiThreadZipper(thisSession.uVFS, retr,thisSession.uiSG("current_dir"),2000);
          write_command_http("Connection: close");
          done = true;
        }
        else
        {
          long content_length = 0;
          try{content_length = otherFile.length();}catch(Exception e){}
          if (byteRanges.size() == 1)
          {
            Properties p = (Properties)byteRanges.elementAt(0);
            write_command_http("Content-Range: "+p.getProperty("start")+"-"+p.getProperty("end")+"/"+content_length);
            write_command_http("Content-Length: "+(htmlData.length()>0?(htmlData.length()+2):Long.parseLong(p.getProperty("end"))-Long.parseLong(p.getProperty("start"))));
          }
          else if (byteRanges.size() <= 1)
          {
            write_command_http("Content-Length: "+(htmlData.length()>0?(htmlData.length()+2):content_length));
          }
          else if (byteRanges.size() > 1)
          {
            long calculatedContentLength = 2;
            for (int x=0; x<byteRanges.size(); x++)
            {
              Properties p = (Properties)byteRanges.elementAt(x);
              calculatedContentLength += ("--"+byteRangeBoundary).length()+2;
              calculatedContentLength += ("Content-Type: "+contentType).length()+2;
              calculatedContentLength += ("Content-range: bytes "+p.getProperty("start")+"-"+p.getProperty("end")+"/"+content_length).length()+2;
              calculatedContentLength += 2;
              calculatedContentLength += Long.parseLong(p.getProperty("end")) - Long.parseLong(p.getProperty("start"));
              calculatedContentLength += 2;
            }
            calculatedContentLength += ("--"+byteRangeBoundary+"--").length()+2;
            write_command_http("Content-Length: "+calculatedContentLength);
          }
          write_command_http("Accept-Ranges: bytes");
        }
        if (forceFileName) write_command_http("Content-Disposition: attachment; filename=\""+otherFile.getName()+"\"");

        write_command_http("");
        if (byteRanges.size() == 0)
        {
          Properties p = new Properties();
          p.put("start","0");
          p.put("end","-1");
          byteRanges.addElement(p);
        }
        long content_length = 0;
        try{content_length = otherFile.length();}catch(Exception e){}
        for (int x=0; x<byteRanges.size(); x++)
        {
          Properties p = (Properties)byteRanges.elementAt(x);
          if (!headersOnly)
          {
            if (quickWrite) write_command_http(htmlData);
            else
            {
              if (byteRanges.size() > 1)//ADOBE PDF plugin does this on XP's IE
              {
                if (x == 0) write_command_http("");
                write_command_http("--"+byteRangeBoundary);
                write_command_http("Content-Type: "+contentType);
                write_command_http("Content-range: bytes "+p.getProperty("start")+"-"+p.getProperty("end")+"/"+content_length);
                write_command_http("");
              }
              thisSession.uiPUT("file_transfer_mode","BINARY");
              retr.data_os = original_os;
              retr.httpDownload = true;

              String the_dir = thisSession.uiSG("current_dir");
              //allow a plugin to alter the logged file name in case it may have altered the incoming the_command_data
              Properties pp = new Properties();
              pp.put("the_dir",the_dir);
              thisSession.runPlugin("transfer_path", pp);
              the_dir = pp.getProperty("the_dir",the_dir);

              retr.init_vars(the_dir, Long.parseLong(p.getProperty("start")), Long.parseLong(p.getProperty("end"))+1, thisSession, item, false, "", otherFile);
              retr.runOnce = true;
              retr.run();
              if (byteRanges.size() > 1) write_command_http("");
            }
          }
        }
        if (byteRanges.size() > 1) write_command_http("--"+byteRangeBoundary+"--");
      }
    }
  }

  public void doServeDir(boolean headersOnly, String error_message, Vector listing, Vector headers, String ifnonematch, boolean closeConnection, boolean forceHTML) throws Exception
  {
    Properties item = thisSession.uVFS.get_item(thisSession.uiSG("current_dir"));
    if(item == null)
    {
      DEAUTH();
      return;
    }

    if (thisSession.BG("WebServerMode"))
    {
      Vector v = new Vector();
      thisSession.uVFS.getListing(v,thisSession.uiSG("current_dir"), false);
      for (int x=0; x<v.size(); x++)
      {
        Properties p = (Properties)v.elementAt(x);
        if (p.getProperty("name").toUpperCase().equals("INDEX.HTML") ||
          p.getProperty("name").toUpperCase().equals("INDEX.HTM"))
        {
          VFS_URL otherFile = new VFS_URL(p,thisSession.uVFS);
          doServeFile(otherFile, headers, ifnonematch, false, false);
          return;
        }
      }
    }
    if (thisSession.BG("DisallowListingDirectories"))
    {
      String msg = LOC.G("<html><body><h1>Directory listing not allowed.</h1><br/>You're not allowed to view this folder..</body></html>");
      write_command_http("HTTP/1.1 403 Not Found");
      write_command_http("Pragma: no-cache");
      write_command_http("Connection: close");
      write_command_http("Content-Length: "+(msg.length()+2));
      write_command_http("");
      write_command_http(msg);
      return;
    }

    write_command_http("HTTP/1.1 200 OK");
    write_command_http("Pragma: no-cache");
    write_standard_headers();

    String outputMode = "xml";
    outputMode = thisSession.server_item.getProperty("httpFormat","HTML").toLowerCase();
    if (forceHTML) outputMode = "html";
    write_command_http("Content-Type: text/"+outputMode+";charset=utf-8");

    String content = "";
    try{content = server_status_frame.get_dir_list_url4_0(outputMode,thisSession.uiSG("user_name"),thisSession.uiSG("current_password"),thisSession.uiSG("listen_ip_port"),thisSession,error_message,item.getProperty("privs",""),proxy, listing);}catch(Exception e){Common.debug(1,e);}
    write_command_http("Content-Length: "+(write_command_http_size(content)));
    write_command_http("Cache-Control: post-check=1,pre-check=1");
    if (closeConnection) write_command_http("Connection: Close");
    write_command_http("");
    if (!headersOnly)write_command_http(content);
  }

  public boolean doPutFile(long content_length, boolean connectionClose) throws Exception
  {
    boolean ok = false;
    if (thisSession.check_access_privs(thisSession.uiSG("current_dir"), "STOR") && Common.filter_check("U", Common.last(thisSession.uiSG("current_dir")), server_status_frame.SG("filename_filters_str")))
      ok = true;
    Properties dir_item = thisSession.uVFS.get_item(thisSession.uiSG("current_dir"));
    if (dir_item == null) dir_item = thisSession.uVFS.get_item_parent(thisSession.uiSG("current_dir"));
    if (ok)
    {
      if (stor_Thread == null) stor_Thread = new Thread(stor);
      Socket local_s = Common.getSTORSocket(thisSession, stor, stor_Thread, "");
      OutputStream of_stream = local_s.getOutputStream();
      thisSession.uVFS.reset();
      if (content_length > 0 || connectionClose)
      {
        if (content_length > 0) connectionClose = false;//if we have a content length, use that instead
        try
        {
          byte[] b = new byte[bufferSize];
          int bytes_read = 0;
          while ((connectionClose || content_length > 0) && bytes_read >= 0)
          {
            if (!connectionClose && content_length < b.length) b = new byte[(int)content_length];
            bytes_read = original_is.read(b);
            if (bytes_read > 0)
            {
              content_length -= bytes_read;
              of_stream.write(b,0,bytes_read);
            }
          }
          of_stream.flush();
        }
        catch(Exception e)
        {
          Common.debug(1,e);
        }
      }
      try{of_stream.close();}catch(Exception e){}
      if (stor.active) {try{while (stor.active) Thread.sleep(100);}catch(Exception e){}}
      try{local_s.close();}catch(Exception e){}
    }
    else//discard data
    {
      get_raw_http_command((int)content_length);
    }
    thisSession.uVFS.reset();
    if (ok) //allow full access to this file since this session just uploaded it
    {
      Properties item = thisSession.uVFS.get_item(thisSession.uiSG("current_dir"));
      thisSession.accessExceptions.put(thisSession.uiSG("current_dir"),item);
    }
    return ok;
  }

  public String doPropFind(Properties commandActions, String depth, boolean listProps, Vector fieldOrder) throws Exception
  {
    if (!thisSession.uiSG("current_dir").toUpperCase().startsWith(thisSession.SG("root_dir").toUpperCase())) thisSession.uiPUT("current_dir",thisSession.SG("root_dir") + (thisSession.uiSG("current_dir").startsWith("/")?thisSession.uiSG("current_dir").substring(1):thisSession.uiSG("current_dir")));

    Element root = new Element("multistatus","DAV:");
    Document doc = new Document(root);

    Properties item = thisSession.uVFS.get_item(thisSession.uiSG("current_dir"));
    if (item == null)
    {
      return null;
    }
    else
    {
      if (item.getProperty("type").toUpperCase().equals("DIR") && !thisSession.uiSG("current_dir").endsWith("/"))
        thisSession.uiPUT("current_dir",thisSession.uiSG("current_dir")+"/");
      Vector items = new Vector();
      if (!depth.equals("0"))
      {
        if (depth.indexOf("inf")>=0) thisSession.uVFS.getListing(items,thisSession.uiSG("current_dir"),999,10000,false,true);
        else if (depth.equals("1")) thisSession.uVFS.getListing(items,thisSession.uiSG("current_dir"));
        Properties p = new Properties();
        p.put("listing",items);
        thisSession.runPlugin("list",p);
      }
      items.insertElementAt(item,0);
      Vector hrefs = new Vector();
      boolean listAdditionalProps = false;
      for(int x=0; x<items.size(); x++)
      {
        item = (Properties)items.elementAt(x);
        String parentPrivs = thisSession.uVFS.get_item(thisSession.uiSG("current_dir")).getProperty("privs","");
        if (item.getProperty("privs").toLowerCase().indexOf("(invisible)") < 0 && parentPrivs.toLowerCase().indexOf("(view)") >= 0)
        {
          if(item.getProperty("name").startsWith(".") && !item.getProperty("name").equalsIgnoreCase(".VolumeIcon.icns") && items.size() > 1)
          {
            //invisible items are hidden from listings, but not when queried directly
            continue;
          }

          Element href = new Element("href","D","DAV:");
          String dir = thisSession.uiSG("current_dir");
          if (!thisSession.SG("root_dir").equals("/")) dir = dir.substring(thisSession.SG("root_dir").length()-1);
          if (!depth.equals("0") && x > 0) href.setText(Common.url_encode(dir,"/")+Common.url_encode(item.getProperty("name","")));
          else href.setText(Common.url_encode(dir,"/"));
          if (depth.indexOf("inf") >= 0)
          {
            dir = item.getProperty("root_dir");
            if (dir.startsWith(SG("root_dir"))) dir = dir.substring(SG("root_dir").length()-1);
            href.setText(Common.url_encode(dir,"/")+Common.url_encode(item.getProperty("name","")));
          }
          if (hrefs.indexOf(href.getText()) < 0)
          {
            hrefs.addElement(href.getText());

            Element response = new Element("response","D", "DAV:");
            response.addNamespaceDeclaration(root.getNamespace());

            root.addContent(response);
            response.addContent(href);

            Element propstatGood = new Element("propstat","D","DAV:");
            Element propstatBad = new Element("propstat","D","DAV:");
            Element propGood = new Element("prop","D","DAV:");
            Element propBad = new Element("prop","D","DAV:");
            propstatGood.addContent(propGood);
            propstatBad.addContent(propBad);
            Element error404 = new Element("status","D","DAV:").setText("HTTP/1.1 404 Not Found");
            long quota = -12345;
            long total_quota = -12345;
            try{quota=thisSession.get_quota_used(thisSession.uiSG("current_dir"));}catch(Exception e){}
            try{total_quota=thisSession.get_total_quota(thisSession.uiSG("current_dir"));}catch(Exception e){}

            if (commandActions.size() == 0)
            {
              //this is a request to get all supported props, so put them all in
              commandActions.put("getcontentlength","");
              commandActions.put("getlastmodified","");
              commandActions.put("modificationdate","");
              fieldOrder.addElement("getcontentlength");
              fieldOrder.addElement("getlastmodified");
              fieldOrder.addElement("modificationdate");
              if (item.getProperty("type").toUpperCase().equals("DIR"))
              {
                commandActions.put("resourceType","");
                fieldOrder.addElement("resourceType");
                if (quota != -12345)
                {
                  commandActions.put("quota","");
                  commandActions.put("quotaused","");
                  if (fieldOrder.indexOf("quota") < 0) fieldOrder.addElement("quota");
                  if (fieldOrder.indexOf("quotaused") < 0) fieldOrder.addElement("quotaused");
                }
              }
              listAdditionalProps = true;
            }


            if (quota == -12345) quota = 0;
            if (total_quota == -12345) total_quota = 300*1024*1024;

            Enumeration keylist = commandActions.keys();
            boolean useGood = false;
            boolean useBad = false;
            if (listProps)
            {
              Properties commandActions2 = (Properties)proppatches.get(new VFS_URL(item,thisSession.uVFS).getFile().getCanonicalPath());
              if (new VFS_URL(item,thisSession.uVFS).getFile().exists())
              {
                for (int xx=0; xx<fieldOrder.size(); xx++)
                {
                  String key = fieldOrder.elementAt(xx).toString();
                  if (commandActions2.containsKey(key))
                  {
                    //String val = commandActions2.getProperty(key);
                    useGood = true;
                    Element elementKey = new Element(key,"http://www.apple.com/SyncServices");
                    propGood.addContent(elementKey);
                    //elementKey.setText(val);
                  }
                }
              }
            }
            else
            {
              for (int xx=0; xx<fieldOrder.size(); xx++)
              {
                String key = fieldOrder.elementAt(xx).toString();
                if (key.equalsIgnoreCase("getlastmodified"))
                {
                  useGood = true;
                  Element getlastmodified = new Element(key,"D","DAV:");
                  propGood.addContent(getlastmodified);
                  getlastmodified.setText(sdf_rfc1123.format(new Date(Long.parseLong(item.getProperty("modified","0")))));
                }
                else if (key.equalsIgnoreCase("modificationdate"))
                {
                  useGood = true;
                  Element getlastmodified = new Element(key,"D","DAV:");
                  propGood.addContent(getlastmodified);
                  getlastmodified.setText(sdf_rfc1123_2.format(new Date(Long.parseLong(item.getProperty("modified","0")))));
                }
                else if (key.equalsIgnoreCase("resourcetype") && item.getProperty("type").toUpperCase().equals("DIR"))
                {
                  useGood = true;
                  if (item.getProperty("type").toUpperCase().equals("DIR")) propGood.addContent(new Element("resourcetype","D","DAV:").addContent(new Element("collection","D","DAV:")));
                  else propGood.addContent(new Element("resourcetype","D","DAV:"));
                }
                else if (key.equalsIgnoreCase("getcontentlength"))
                {
                  if (item.getProperty("type").toUpperCase().equals("DIR"))
                  {
                    useBad = true;
                    propBad.addContent(new Element(key,"D","DAV:"));
                    if (!propstatBad.isAncestor(error404))propstatBad.addContent(error404);
                  }
                  else
                  {
                    propGood.addContent(new Element(key,"D","DAV:").setText(item.getProperty("size","0")));
                    useGood = true;
                  }
                }
                else if (key.equalsIgnoreCase("quota"))
                {
                  if (!item.getProperty("type").toUpperCase().equals("DIR"))
                  {
                    useBad = true;
                    propBad.addContent(new Element(key,"D","DAV:"));
                    if (!propstatBad.isAncestor(error404))propstatBad.addContent(error404);
                  }
                  else
                  {
                    propGood.addContent(new Element(key,"D","DAV:").setText(((total_quota*2)/1024)+""));
                    useGood = true;
                  }
                }
                else if (key.equalsIgnoreCase("quotaused"))
                {
                  if (!item.getProperty("type").toUpperCase().equals("DIR"))
                  {
                    useBad = true;
                    propBad.addContent(new Element(key,"D","DAV:"));
                    if (!propstatBad.isAncestor(error404))propstatBad.addContent(error404);
                  }
                  else
                  {
                    propGood.addContent(new Element(key,"D","DAV:").setText(((quota*2)/1024)+""));
                    useGood = true;
                  }
                }
                else if (key.equalsIgnoreCase("dotunderscore"))
                {
                  propGood.addContent(new Element(key,"A","http://www.apple.com/webdav_fs/props/").setText(""));
                  useGood = true;
                }
                else if (key.equalsIgnoreCase("dotunderscore-size"))
                {
                  propGood.addContent(new Element(key,"A","http://www.apple.com/webdav_fs/props/").setText("0"));
                  useGood = true;
                }
                else if (key.equalsIgnoreCase("current-user-privilege-set_________________"))
                {
                  //   http://www.ietf.org/rfc/rfc3744.txt
                  Element cups = new Element(key,"P","DAV:");
                  propGood.addContent(cups);


                  Element privilege = new Element("privilege","D","DAV:");
                  privilege.addContent(new Element("read","D","DAV:"));
                  cups.addContent(privilege);

                  privilege = new Element("privilege","D","DAV:");
                  privilege.addContent(new Element("write-internal","I","http://idisk.mac.com/_namespace"));
                  cups.addContent(privilege);

//                  privilege = new Element("privilege","D","DAV:");
//                  privilege.addContent(new Element("manage","I","http://idisk.mac.com/_namespace"));
//                  cups.addContent(privilege);


                  /*
                  if (item.getProperty("privs").indexOf("(read)") >= 0)
                  {
                    Element privilege = new Element("privilege","D","DAV:");
                    privilege.addContent(new Element("read","D","DAV:"));
                    cups.addContent(privilege);
                  }
                  if (item.getProperty("privs").indexOf("(write)") >= 0)
                  {
                    Element privilege = new Element("privilege","D","DAV:");
                    privilege.addContent(new Element("write","D","DAV:"));
                    cups.addContent(privilege);
                  }
                  if (item.getProperty("privs").indexOf("(delete)") >= 0)
                  {
                    Element privilege = new Element("privilege","D","DAV:");
                    privilege.addContent(new Element("delete","D","DAV:"));
                    cups.addContent(privilege);
                  }
                  */
                  useGood = true;
                }
                else
                {
                  useBad = true;
                  Element empty = new Element(key,"D","DAV:");
                  propBad.addContent(empty);
                  if (!propstatBad.isAncestor(error404))propstatBad.addContent(error404);
                }
              }
              if (listAdditionalProps)
              {
                Properties commandActions2 = (Properties)proppatches.get(new VFS_URL(item,thisSession.uVFS).getFile().getCanonicalPath());
                if (commandActions2 != null)
                {
                  Enumeration additionalKeyList = commandActions2.keys();
                  while(additionalKeyList.hasMoreElements())
                  {
                    String key = additionalKeyList.nextElement().toString();
                    String val = commandActions2.getProperty(key);
                    useGood = true;
                    Element elementKey = new Element(key,"X","http://www.apple.com/SyncServices");
                    propGood.addContent(elementKey);
                    elementKey.setText(val);
                  }
                }
              }
            }
            if (useGood) propstatGood.addContent(new Element("status","D","DAV:").setText("HTTP/1.1 200 OK"));
            if (useGood) response.addContent(propstatGood);
            if (useBad && !listAdditionalProps) response.addContent(propstatBad);//we don't list bad props if they were just asking for a list of all good props.
          }
        }
      }
    }

    if (xmlOut == null)
    {
        xmlOut = new XMLOutputter();
        Format f = Format.getPrettyFormat();
        f.setExpandEmptyElements(false);
        //f.setIndent("\t");
        xmlOut.setFormat(f);
    }
    return xmlOut.outputString(doc);
  }

  public Vector get_http_post_items(String boundary, long max_len) throws Exception
  {
    Properties metaInfo = new Properties();
    boolean speedCheat = false; //if we find a specific POST data field item, we know its a single file transfer, and dont' bother checkign for the boundary till near the end.
    //it allows us to cheat in a special case scenario and achieve much higher bandwidth with HTTP uploads.
    Vector items = new Vector();
    Properties item = null;
    String data = "";
    boolean start_new_item = false;
    long len = 4;//for one blank line already read, and 2 more for the ending "--" on the last boundary
    boolean dataAlreadyRead = false;
    while(true)
    {
      if (boundary.equals("")) break;
      if (!dataAlreadyRead)
      {
        data = get_http_command();len += data.length()+2;data = data.trim();data = new String(data.getBytes(),"UTF8");data = Common.url_decode(data);
      }
      dataAlreadyRead = false;

      if (data.endsWith(boundary)) start_new_item = true;
       if (data.endsWith(boundary+"--")) break;
      if (start_new_item)
      {
        item = new Properties();
        items.addElement(item);
        data = get_http_command();len += data.length()+2;data = data.trim();data = new String(data.getBytes(),"UTF8");data = Common.url_decode(data);
        String name = data.substring(data.indexOf("name=\"")+6,data.indexOf("\"",data.indexOf("name=\"")+6));
        if (name.endsWith("_SINGLE_FILE_POST")) speedCheat = true;
        if (max_len < (bufferSize * 10)) speedCheat = false;
        if (data.indexOf("filename") >= 0)
        {
          System.getProperties().put("crushftp.activeUpload.info"+thisSession.uiSG("CrushAuth"),"PROGRESS:"+len+"/"+max_len+";");
          item.put("type","file");
          String upload_item = data.substring(data.indexOf("filename=\"")+10,data.indexOf("\"",data.indexOf("filename=\"")+10));
          if (upload_item.indexOf("\\") >= 0) upload_item = upload_item.replace('\\','/');
          if (upload_item.indexOf("/") >= 0) upload_item = thisSession.last(upload_item);
          Properties p = new Properties();
          item.put("file",p);
          p.put("filename",upload_item);
          data = get_http_command();len += data.length()+2;data = data.trim();data = new String(data.getBytes(),"UTF8");data = Common.url_decode(data);
          p.put("encoding",data);
          get_http_command();len += 2;//blank line

          boolean ok = false;
          if (thisSession.check_access_privs(thisSession.uiSG("current_dir")+upload_item, "STOR") && Common.filter_check("U", Common.last(thisSession.uiSG("current_dir")+upload_item), server_status_frame.SG("filename_filters_str")))
          {
            ok = true;
          }
          else
          {
            stor.stop_message = LOC.G("Access denied. (You do not have permission or the file extension is not allowed.)");
            System.getProperties().put("crushftp.activeUpload.info"+thisSession.uiSG("CrushAuth"),stor.stop_message);
            item.put("callback",stor.stop_message);
          }
          if (upload_item.equals("")) ok = false;
          if (ok)
          {
            System.getProperties().put("crushftp.activeUpload.info"+thisSession.uiSG("CrushAuth"),"PROGRESS:"+len+"/"+max_len+";");
            if (stor_Thread == null) stor_Thread = new Thread(stor);
            Socket local_s = Common.getSTORSocket(thisSession, stor, stor_Thread, upload_item);
            OutputStream of_stream = local_s.getOutputStream();
            try
            {
              byte buffer[] = new byte[bufferSize*2];
              byte boundaryBytes[] = ("\r\n--"+boundary).getBytes();
              int len1 = 0;
              int len2 = 0;
              byte[] b = new byte[bufferSize];
              int bytes_read = 0;
              original_is.mark(0);
              thisSession.uiPPUT("file_length",max_len-len);
              while ((speedCheat || findSeparator(boundaryBytes,buffer,len1,len2) < 0) && bytes_read >= 0)
              {
                System.getProperties().put("crushftp.activeUpload.info"+thisSession.uiSG("CrushAuth"),"PROGRESS:"+len+"/"+max_len+";");
                original_is.reset();//go back to the position two reads ago
                if (len1 > 0 && len2 > 0)
                {
                  of_stream.write(buffer,0,len1);
                  len += len1;
                  original_is.skip(len1);//skip forward past the data that has been written to disk
                  original_is.mark(b.length*3);//mark it so that two entire reads can be re-read when needed
                  original_is.skip(len2);//skip forward again to the last read location
                  System.arraycopy(buffer,bufferSize,buffer,0,len2);len1=len2;
                }
                else
                {
                  System.arraycopy(buffer,bufferSize,buffer,0,len2);len1=len2;
                  original_is.mark(b.length*3);//mark it so that two entire reads can be re-read when needed
                  original_is.skip(bytes_read);//skip forward again to the last read location
                }
                bytes_read = original_is.read(b);
                if (bytes_read > 0){System.arraycopy(b,0,buffer,bufferSize,bytes_read);len2=bytes_read;}
                //when we get close to the end of our post, then start checking for the boundary if speedCheat was on.
                if (max_len - len < bufferSize*4) speedCheat = false;

              }
              original_is.reset();//reset it back two reads
              int loc = findSeparator(boundaryBytes,buffer,len1,len2);
              if (loc < bufferSize)
              {
                of_stream.write(buffer,0,loc);len += loc;
                original_is.skip((long)loc);
              }
              else
              {
                of_stream.write(buffer,0,len1);len += len1;
                of_stream.write(buffer,bufferSize,loc-bufferSize);len += loc-bufferSize;
                original_is.skip((long)loc-bufferSize);
              }
            }
            catch(Exception e)
            {
              Common.debug(1,e);
              keepGoing = false;
              done = true;
              len = max_len;
            }
            try{of_stream.close();}catch(Exception e){}
            while (stor.active) Thread.sleep(100);
            try{stor.v.close();}catch(Exception e){}
            local_s.close();
            thisSession.uVFS.reset();
            if (thisSession.uiPG("lastUploadStat") != null) thisSession.uiPG("lastUploadStat").put("metaInfo",metaInfo);
          }
          if (stor.stop_message.length() > 0) System.getProperties().put("crushftp.activeUpload.info"+thisSession.uiSG("CrushAuth"),stor.stop_message);
          else System.getProperties().remove("crushftp.activeUpload.info"+thisSession.uiSG("CrushAuth"));
        }
        else
        {
          item.put("type","text");
          data = get_http_command();len += data.length()+2;data = data.trim();data = new String(data.getBytes(),"UTF8");data = Common.url_decode(data);
          //read till we hit a boundary
          String data_item = "";
          dataAlreadyRead = true;
          while(true)
          {
            data = get_http_command();len += data.length()+2;data = data.trim();data = new String(data.getBytes(),"UTF8");data = Common.url_decode(data);

            if (data.endsWith(boundary)) break;
            if (data.endsWith(boundary+"--")) break;
            if (len >= max_len) break;
            data_item += data+CRLF;
          }
          data_item = data_item.substring(0,data_item.length()-2);
          item.put(name, data_item);
          if (name.toUpperCase().startsWith("META_"))
          {
            thisSession.add_log_formatted(name.substring(5)+":"+data_item,"POST");
            metaInfo.put(name.substring(5),data_item);
          }
        }
        start_new_item = false;
      }
      if (len >= max_len) break;//this may be off in cases where UTF8 data is sent as the resulting bytes will be less than the original actual bytes
    }
    return items;
  }

  protected int findByte(byte value, byte[] buffer, int start_pos, int len1, int len2)
  {
    int loc = start_pos;
    while (loc < len2)
    {
      if (loc == len1) loc = bufferSize;
      if (buffer[loc] == value) return loc;
      loc++;
    }
    return -1;
  }

  protected int findSeparator(byte[] boundary, byte[] buffer, int len1, int len2)
  {
    len2+=bufferSize;
    int start_pos = 0;
    while(start_pos >= 0)
    {
      int loc = findByte(boundary[0],buffer, start_pos, len1, len2);
      start_pos = loc;
      if (start_pos >= 0) start_pos++;
      if (loc < 0) return -1;
      if (loc > len2-boundary.length) return -1;
      int boundary_loc = 0;
      while(loc < buffer.length)
      {
        loc++;
        if (loc == buffer.length || loc == len2) break;
        boundary_loc++;
        if (boundary_loc == boundary.length)
        {
          return loc-boundary.length;
        }
        if (loc == len1) loc = bufferSize;
        if (buffer[loc] != boundary[boundary_loc]) break;
      }
    }
    return -1;
  }

  public boolean wait_for_bytes() throws Exception
  {
    boolean result = true;
    start_idle_thread();
    byte[] aByte = new byte[1];
    if (!thisSession.uiBG("secure"))
    {
      //wait 2 minute for http data, then kill it if nothing has been received.
      while(sock.isConnected() && !sock.isInputShutdown() && !sock.isOutputShutdown() && original_is.available() == 0 )
      {
        original_is.mark(2);
        if (original_is.read(aByte) < 0)
        {
          try{original_is.close();}catch(Exception e){}
          result = false;
          break;
        }
        original_is.reset();
        Thread.sleep(100);
      }
    }
    stop_idle_thread();
    return result;
  }

  public Vector getHeaders() throws Exception
  {
    Vector headers = new Vector();
    try
    {
      String headerStr = "";
      int bytesRead = 0;
      if (wait_for_bytes())
      {
        start_idle_thread();
        original_is.mark(128000);
        while (bytesRead >= 0)
        {
          bytesRead = original_is.read(headerBytes);
          if (bytesRead > 0)
          {
            headerStr += new String(headerBytes,0,bytesRead);
          }
          if (headerStr.indexOf("\r\n\r\n") >= 0 || headerStr.length() > 128000) break;
        }
        stop_idle_thread();
      }
      if (headerStr.equals(""))
      {
        done = true;
      }
      else
      {
        bytesRead = headerStr.indexOf("\r\n\r\n")+4;
        original_is.reset();
        original_is.skip(bytesRead);
        headerStr = headerStr.substring(0,bytesRead).trim();
        headerStr = Common.url_decode(headerStr);
        BufferedReader bsr = new BufferedReader(new StringReader(headerStr));
        String data = "";
        if (log != null) log.write(("\r\n\r\n"+Thread.currentThread().getName()+new Date()+"\r\n").getBytes());
        while ((data=bsr.readLine()) != null)
        {
          data = data.trim();
          headers.addElement(data);
          thisSession.add_log_formatted(data,(data+" ").substring(0,(data+" ").indexOf(" ")));
          if (log != null) log.write((Thread.currentThread().getName()+data+"\r\n").getBytes());
        }
      }
    }
    catch(Exception e)
    {
      Common.debug(1,e);
      if (headers.size() == 0) done = true;
      else throw e;
    }
    return headers;
  }

  public String get_raw_http_command(int amount) throws Exception
  {
    String data = "";

    start_idle_thread();
    while ((data.indexOf("\r\n") < 0 && amount < 0 && data.length()<bufferSize) || (amount > 0 && data.length()<amount))
    {
      if (!wait_for_bytes()) return "";

      byte[] aByte = new byte[1];
      if (amount > 0 && amount-data.length() >= aByte.length) aByte = new byte[bufferSize];
      if (amount > 0 && amount-data.length() < aByte.length) aByte = new byte[amount];

      int bytesRead = 0;
      if (amount < 0)
      {
        aByte = headerBytes;
        original_is.mark(70000);
        bytesRead = original_is.read(aByte);
        if (bytesRead > 0)
        {
          String s = new String(aByte,0,bytesRead);
          bytesRead = s.indexOf("\r\n")+2;
          original_is.reset();
          original_is.skip(bytesRead);
        }
      }
      else
      {
        bytesRead = original_is.read(aByte);
      }
      if (bytesRead < 0)
      {
        try{original_is.close();}catch(Exception e){}
        stop_idle_thread();
        return "";
      }
      data += new String(aByte,0,bytesRead);
    }
    thisSession.thread_killer_item.last_activity = new Date().getTime();
    stop_idle_thread();
    if (log != null) log.write((Thread.currentThread().getName()+data).getBytes());
    if (amount >= 0 && log != null) log.write("\r\n\r\n".getBytes());
    return data;
  }

  String direction = "";
  public String get_http_command() throws Exception
  {
    String data = get_raw_http_command(-1);
    data = data.trim();
    data = server_status_frame.strip_variables(data,thisSession);
//if (!direction.equals("READ")) {direction = "READ"; System.out.println("--------------------------READ----------------------");}System.out.println(data);
    return data;
  }

  public void write_command_raw(String data) throws Exception
  {
    original_os.write(data.getBytes("UTF8"));
    original_os.flush();
    thisSession.thread_killer_item.last_activity = new Date().getTime();
    if (log != null) log.write((Thread.currentThread().getName()+data).getBytes());
  }

  public int write_command_http_size(String data) throws Exception
  {
    data = server_status_frame.change_vars_to_values(data, thisSession);
    data += CRLF;
    return data.getBytes("UTF8").length;
  }

  public int write_command_http(String data) throws Exception
  {
    data = server_status_frame.change_vars_to_values(data, thisSession);
    if (!data.toUpperCase().startsWith("<"))
    {
      thisSession.add_log("[" + thisSession.uiSG("user_number") + ":" + thisSession.uiSG("user_name") + ":" + thisSession.uiSG("user_ip") + "] WROTE: *" + data.trim() + "*", "HTTP");
    }
    data += CRLF;
    write_command_raw(data);
    if (writeCookieAuth)
    {
      String id = new Date().getTime()+"";
      globalSessions.put(thisSession.uiSG("user_ip")+"_"+id+"_user",thisSession.uiSG("user_name"));
      globalSessions.put(thisSession.uiSG("user_ip")+"_"+id+"_pass",thisSession.uiSG("current_password"));
      write_command_raw("Set-Cookie: CrushAuth="+id+"; path=/"+CRLF);
      thisSession.uiPUT("CrushAuth",id);//needed to allow XML to work with Safari since it can't access cookies (CrushUpplet)
      thisSession.uiPUT("login_date_stamp",id);
      writeCookieAuth = false;
    }
//if (!direction.equals("WRITE")) {direction = "WRITE"; System.out.println("--------------------------WRITE----------------------");}System.out.print(data);
    return data.length();
  }

  public String SG(String data)
  {
    return thisSession.SG(data);
  }

  public void write_standard_headers() throws Exception
  {
    write_command_http("Server: "+server_header);
    write_command_http("x-responding-server: sslngn018");
    write_command_http("X-dmUser: "+SG("username"));
    write_command_http("Date: " + sdf_rfc1123.format(new Date()));
    if (done) write_command_http("Connection: close");
    else write_command_http("Connection: Keep-Alive");
  }

  public void write_standard_headers_1_0() throws Exception
  {
    write_command_http("Date: " + sdf_rfc1123.format(new Date()));
    write_command_http("Server: "+server_header);
    write_command_http("Connection: close");
  }

  public void addSessionCommand(String the_command, String the_command_data)
  {
    Properties pp = new Properties();
    pp.put("the_command",the_command);
    pp.put("the_command_data",the_command_data);
    pp.put("user_time",server_status_frame.logDateFormat.format(new Date()));
    pp.put("display",pp.getProperty("user_time")+" | "+the_command + " " + the_command_data);
    pp.put("stamp",new Date().getTime()+"");
    thisSession.uiVG("session_commands").addElement(pp);
  }

  public void DEAUTH() throws Exception
  {
    write_command_http("HTTP/1.1 401 Unauthorized");
    write_command_http("Pragma: no-cache");
    write_command_http("Connection: close");
    write_command_http("WWW-Authenticate: Basic realm=\""+hostString+"\"");
    write_command_http("Content-Type: text/html;charset=utf-8");
    write_command_http("Set-Cookie: CrushAuth=credentials; path=/");
    thisSession.uiPUT("CrushAuth","credentials");//needed to allow XML to work with Safari since it can't access cookies (CrushUpplet)
    write_command_http("Content-Length: "+"Unauthorized".length());
    write_command_http("");
    write_command_raw("Unauthorized");
    thisSession.uVFS = null;
    done = true;
  }

  public void fixRootDir(String domain)
  {
    try
    {
      if (thisSession == null || thisSession.uVFS == null) return;
      thisSession.setupRootDir(domain);
    }
    catch(Exception e)
    {
      Common.debug(1,e);
    }
  }

  public void sendRedirect(String path, Vector headers) throws Exception
  {
    write_command_http("HTTP/1.0 302 Redirect");
    write_command_http("Pragma: no-cache");
    //get host string to put in location.
    String baseURL = getBaseUrl(headers);
    if (path.toUpperCase().startsWith("HTTP")) write_command_http("location: "+path);
    else write_command_http("location: "+baseURL+path);
  }

  public String getBaseUrl(Vector headers)
  {
    for(int xx=0; xx<headers.size(); xx++)
    {
      String data2 = headers.elementAt(xx).toString();
      if (data2.toUpperCase().startsWith("HOST: ") || data2.toUpperCase().startsWith("X-FORWARDED-HOST: "))
      {
        hostString = data2.substring(data2.toUpperCase().indexOf(":") + 1).trim();
      }
    }
    return server_item.getProperty("serverType","http")+"://" + hostString+proxy;
  }

  public void sendHttpsRedirect(String path, Vector headers) throws Exception
  {
    write_command_http("HTTP/1.0 302 Redirect");
    write_command_http("Pragma: no-cache");
    //get host string to put in location.
    for(int xx=0; xx<headers.size(); xx++)
    {
      String data2 = headers.elementAt(xx).toString();
      if (data2.toUpperCase().startsWith("HOST: ") || data2.toUpperCase().startsWith("X-Forwarded-Host: "))
      {
        hostString = data2.substring(data2.toUpperCase().indexOf(":") + 1).trim();
      }
    }
    if (hostString.indexOf(":") >= 0) hostString = hostString.substring(0,hostString.indexOf(":"));
    Vector server_list = (Vector)thisSession.server_status_frame.server_settings.get("server_list");
    String port = "443";
    for (int x=0; x<server_list.size(); x++)
    {
      Properties p = (Properties)server_list.elementAt(x);
      if (p.getProperty("serverType","FTP").equalsIgnoreCase("HTTPS"))
      {
        port = p.getProperty("port","443");
        break;
      }
    }
    if (port.equals("443")) port = "";
    else port = ":"+port;
    write_command_http("location: https://" + hostString+port+proxy+path);
  }

  class idleChecker implements Runnable
  {
    int secs;
    public idleChecker(int secs)
    {
      this.secs = secs;
    }
    public void run()
    {
      try
      {
        Thread.sleep(secs*1000);
        do_kill();
      }
      catch(Exception e)
      {
      }
    }
  }

  Thread idle_thread = null;

  public void start_idle_thread()
  {
    if (idle_thread != null)
    {
      idle_thread.interrupt();
    }
    idle_thread = new Thread(new idleChecker(timeoutSeconds));
    idle_thread.start();
  }

  public void stop_idle_thread()
  {
    if (idle_thread != null)
    {
      idle_thread.interrupt();
    }
  }

  public void updateMimes() throws Exception
  {
    long mimesModifiedNew = new File(System.getProperty("crushftp.web")+"WebInterface/mime_types.txt").lastModified();
    if (mimesModified != mimesModifiedNew)
    {
      mimes = new Properties();
      BufferedReader mimeIn = new BufferedReader(new FileReader(new File(System.getProperty("crushftp.web")+"WebInterface/mime_types.txt")));
      String s = mimeIn.readLine();
      while(s != null)
      {
        if (!s.startsWith("#")) try{mimes.put(s.substring(0,s.indexOf(" ")).trim().toUpperCase(),s.substring(s.indexOf(" ")+1).trim());}catch(Exception e){/*bad mime type*/}
        s = mimeIn.readLine();
      }
      mimeIn.close();
    }
  }

  public void processMiniURLs(String header0,Vector headers)
  {
    try
    {

      if (header0.toUpperCase().startsWith("GET "))
      {
        String data = header0.substring(header0.indexOf(" ")+1,header0.lastIndexOf(" "));
        String miniURL = data.substring(data.lastIndexOf("/")+1);//miniURL piece
        Vector miniURLs = thisSession.server_status_frame.VG("miniURLs");
        if (miniURLs != null)
        {
          for (int x=0; x<miniURLs.size(); x++)
          {
            Properties p = (Properties)miniURLs.elementAt(x);
            if (p.getProperty("key","").equalsIgnoreCase(miniURL))//found a match, translate it
            {
              boolean expired = false;
              SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm aa");
              try
              {
                if(!p.getProperty("expire","").equals(""))
                {
                  if (sdf.parse(p.getProperty("expire","")).getTime() < new Date().getTime()) expired = true;
                }
              }
              catch(Exception e)
              {
                expired = true;
              }
              if (expired)
              {
                miniURLs.removeElementAt(x);
                Common.addCommand("save_server_settings",null);
              }
              else
              {
                String user = p.getProperty("user","");
                String pass = common_code.decode_pass(p.getProperty("pass",""));
                String id = new Date().getTime()+"";
                globalSessions.put(thisSession.uiSG("user_ip")+"_"+id+"_user",user);
                globalSessions.put(thisSession.uiSG("user_ip")+"_"+id+"_pass",pass);
                sendRedirect(p.getProperty("redirect","/"),headers);
                write_command_http("Connection: close");
                write_command_http("Set-Cookie: CrushAuth="+id+"; path=/");
                thisSession.uiPUT("CrushAuth",id);
                write_command_http("");
                done = true;
                thisSession.uVFS = null;
              }
              break;
            }
          }
        }
      }
    }
    catch(Exception e)
    {
      Common.debug(1,e);
    }
  }

  public void savePropPatches() throws Exception
  {
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(System.getProperty("crushftp.backup")+"backup/proppatches.prop.save"));
    oos.writeObject(proppatches);
    oos.close();

    new File(System.getProperty("crushftp.backup")+"backup/proppatches.prop").delete();
    new File(System.getProperty("crushftp.backup")+"backup/proppatches.prop.save").renameTo(new File(System.getProperty("crushftp.backup")+"backup/proppatches.prop"));
  }

  public void savePublicPasswords() throws Exception
  {
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(System.getProperty("crushftp.backup")+"backup/publicpasswords.prop.save"));
    oos.writeObject(publicpasswords);
    oos.close();

    new File(System.getProperty("crushftp.backup")+"backup/publicpasswords.prop").delete();
    new File(System.getProperty("crushftp.backup")+"backup/publicpasswords.prop.save").renameTo(new File(System.getProperty("crushftp.backup")+"backup/publicpasswords.prop"));
  }

  public void saveLockTokens() throws Exception
  {
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(System.getProperty("crushftp.backup")+"backup/locktokens.prop.save"));
    oos.writeObject(locktokens);
    oos.close();

    new File(System.getProperty("crushftp.backup")+"backup/locktokens.prop").delete();
    new File(System.getProperty("crushftp.backup")+"backup/locktokens.prop.save").renameTo(new File(System.getProperty("crushftp.backup")+"backup/locktokens.prop"));
  }

  public String changeUser(String xml)
  {
    String username = xml.substring(xml.indexOf("username = ")+"username = ".length(),xml.indexOf(";",xml.indexOf("username = ")));
    String password = xml.substring(xml.indexOf("password = ")+"password = ".length(),xml.indexOf(";",xml.indexOf("password = ")));
    done = true;//force connection closed after validating user
    VFS uVFS = thisSession.uVFS;
    thisSession.uVFS = null;
    boolean ok = thisSession.verify_user(username.trim(),password.trim());
    if (thisSession.uVFS == null) thisSession.uVFS = uVFS;
    done = true;
    if (ok)
    {
      thisSession.uiPUT("current_password",password);
      thisSession.uiPUT("user_name",username);
      this_thread.setName(thisSession.uiSG("user_name") + ":(" + thisSession.uiSG("user_number") + ")-" + thisSession.uiSG("user_ip") + " (control)");
      return username;
    }
    return null;
  }

}
TOP

Related Classes of crushftp.server.Lister

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.
eFormat">java.text.SimpleDateFormat
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.