import java.net.*;

import java.io.*;

 

public class serverRichiesteFTP extends Thread

{

  private static String LogFile="Azioni.log";

  private static String workDir="c:\\Ftpdir";

  private Socket connessione;

  final int porta_FTP_DTP=20;

  final int Porta_com=1188;

  final int Porta_dati=1189;

  String nome_coordinatore=new String();

  int remote_port=20;

  File workingPath;

  ListaFile serverReg=new ListaFile();

 

    

  public serverRichiesteFTP()

  {}

 

  public serverRichiesteFTP(Socket in,ListaFile lf,String co)

  {

     connessione=in;

     serverReg=lf;

     nome_coordinatore=co;

  }

    

  public void run()

  {

     ListaFile temp=new ListaFile();     

     String lista_file[]=new String[60];

     String temp_lista[]=new String[60];

     FileWriter scrittoreLog;

     String messaggio=new String();

     String client_remoto=new String();

     String nome_utente=new String();

     String password_utente=new String();

     String mode_utente=new String();

     String type_utente=new String();

     boolean connesso;

    

     try

     {

       scrittoreLog=new FileWriter(LogFile,true);

       client_remoto=connessione.getInetAddress().toString();

       System.out.println("Connessione stabilita con "+client_remoto);

     scrittoreLog.write("Connessione stabilita con "+client_remoto+"\r\n");

     scrittoreLog.flush();

     connesso=true;

     workingPath=new File(workDir);

    

     //registro alcuni utenti

     this.registraUtenti();

    

     //preparazione alla comunicazione

     connessione.setTcpNoDelay(true);

     //Timeout di tre minuti

     //connessione.setSoTimeout(180000);

     //attesa di 4 minuti per inviare i dati prima della chiusura della socket

     connessione.setSoLinger(true,240);

      BufferedReader comandiIn=new BufferedReader(new InputStreamReader(connessione.getInputStream()));

     PrintWriter comandiOut=new PrintWriter(connessione.getOutputStream(),true);

      

      //invio messaggio di benvenuto

      comandiOut.println("220 Benvenuto!");

      scrittoreLog.write(client_remoto+": invio messaggio di benvenuto\r\n");

      scrittoreLog.flush();

      

      while(connesso)

      {

       messaggio=comandiIn.readLine();

       //visualizza la stringa ricevuta dal client

       //System.out.println(messaggio);

      

       //************************************************/

       //GRUPPO DI COMANDI PER IL CONTROLLO DELL' ACCESSO

       //************************************************/

      

       //COMANDO USER: riceve il nome utente

       if(messaggio.startsWith("USER"))

       {

       //qualsiasi nome è accettato, va verificata la password

       comandiOut.println("331 User name okay, need password.");

       nome_utente=new String(messaggio.substring(4));

       nome_utente=nome_utente.trim();

       }

      

       //COMANDO PASS: riceve la password dell' utente

       if(messaggio.startsWith("PASS"))

       {

       password_utente=new String(messaggio.substring(4));

       password_utente=password_utente.trim();

       if(leggi(new Iscritto(nome_utente,password_utente)))

       {

          comandiOut.println("230 User logged in, proceed.");

          scrittoreLog.write("L\' utente "+nome_utente+" si e\' collegato\r\n");

          System.out.println("L\' utente "+nome_utente+" si e\' collegato");

       }

       else

       {

          comandiOut.println("501 Wrong password.");

          connesso=false;

       }

       }

      

       //COMANDO QUIT: termina la sessione corrente

       if(messaggio.startsWith("QUIT"))

       {

       connesso=false;

       }

      

       //COMANDO ACCT: identifica l' account

       if(messaggio.startsWith("ACCT"))

       {

       //Gestire il comando

       comandiOut.println("502 command not implemented.");

       }

      

       //COMANDO REIN: termina la sessione per l'account-utente attuale e richiede un nuovo accesso

       if(messaggio.startsWith("REIN"))

       {

       //Gestire il comando

       comandiOut.println("502 command not implemented.");

       }

    

       //COMANDO SYST: serve per chiedere il tipo di sistema operativo in uso sul server

       if(messaggio.startsWith("SYST"))

       {

       //Gestire il comando

       comandiOut.println("502 command not implemented.");

       }

 

       //COMANDO NOOP: si invia semplicemente un OK

       if(messaggio.startsWith("NOOP"))

       {

       comandiOut.println("200 OK.");

       }

 

       //**************************************************/

       //GRUPPO DI COMANDI PER I PARAMETRI DI TRASFERIMENTO

       //**************************************************/

      

       //COMANDO TYPE: indica se il trasferimento dei dati è di tipo ASCII o BINARY

       if(messaggio.startsWith("TYPE"))

       {

       //Gestire il comando

       type_utente=new String(messaggio.substring(4));

       type_utente=type_utente.trim();

       if(type_utente.equals("I"))

       {

          comandiOut.println("200 command okay.");

       }

       else if (type_utente.startsWith("A"))

       {

          comandiOut.println("200 command okay.");

          //comandiOut.println("504 command not implemented for that parameter.");

       }

       else if(type_utente.startsWith("E"))

       {

          comandiOut.println("504 command not implemented for that parameter.");

       }

       else if(type_utente.startsWith("L"))

      {

          comandiOut.println("504 command not implemented for that parameter.");

       }

       else

       {

          comandiOut.println("501 Syntax error in parameters or arguments.");

       }

       }

 

       //COMANDO MODE: specifica la modalità di trasferimento dei file: STREAM, BLOCK o COMPRESSED

       if(messaggio.startsWith("MODE"))

       {

       //Gestire il comando

       mode_utente=new String(messaggio.substring(4));

       mode_utente=mode_utente.trim();

       if(mode_utente.equals("S"))

       {

          comandiOut.println("200 ok");

       }

       else if(mode_utente.equals("B")||mode_utente.equals("C"))

       {

          comandiOut.println("504 command not implemented for that parameter.");

       }

       else

       {

          comandiOut.println("501 Syntax error in parameters or arguments.");

       }

       }

 

       //COMANDO PORT: permette di definire il socket lato client

       if(messaggio.startsWith("PORT"))

       {

       int lng,lng1,lng2,ip1,ip2;

       String a1=new String();

       String a2=new String();

       lng = messaggio.length() - 1;

       lng2 = messaggio.lastIndexOf(",");

       lng1 = messaggio.lastIndexOf(",",lng2-1);

       for(int i=lng1+1;i<lng2;i++)

       {

          a1 = a1 + messaggio.charAt(i);

       }

       for(int i=lng2+1;i<=lng;i++)

       {

          a2 = a2 + messaggio.charAt(i);

       }

       ip1 = Integer.parseInt(a1);

       ip2 =Integer.parseInt(a2);

       remote_port = ip1 * 16 *16 + ip2;

       comandiOut.println("200 command okay.");

       }

 

       //***********************************************/

       //GRUPPO DI COMANDI PER IL TRASFERIMENTO DEI FILE

       //***********************************************/

      

       //COMANDO RETR:

       if(messaggio.startsWith("RETR"))

       {

          messaggio=messaggio.substring(4);

       messaggio=messaggio.trim();

       try

       {

         

          System.out.println("L\' utente "+nome_utente+" ha richiesto il file "+messaggio);

          scrittoreLog.write("L\' utente "+nome_utente+" ha richiesto il file "+messaggio+"\r\n");

          scrittoreLog.flush();

          String server_sorgente=new String();

          boolean trovato=false;

          boolean locale=false;

                   

          temp_lista=workingPath.list();

          for(int j=0;j<temp_lista.length;j++)

          {

            if(temp_lista[j]==null)

               {

                 break;

               }

            if(temp_lista[j].equals(messaggio))

               {

                 locale=true;

                 trovato=true;

                 break;

               }

          }

          //System.out.println("file locale: "+locale);

          synchronized(serverReg)

          {

          for(int j=0;((j<serverReg.lista_server.length)&&(!trovato));j++)

            {

            if(serverReg.lista_server[j]==null)

            {

               break;

            }

            for(int i=0;i<serverReg.lista_file_server[j].length;i++)

              {

              if(serverReg.lista_file_server[j][i]==null)break;

              if(serverReg.lista_file_server[j][i].toString().equals(messaggio))

              {

                 trovato=true;

                 server_sorgente=serverReg.lista_server[j];

                 break;

              }

              }//for

            }//for

          }//synchro

            //System.out.println(trovato);System.out.println(server_sorgente);

            if(trovato)

            {

            byte buffer[]=new byte[1024];

          int i;

          //procedura locale

          if(locale)

          {

           try

           {

             comandiOut.println("150 Binary data connection.");

             Socket data_sock=new Socket(connessione.getInetAddress(),remote_port,connessione.getLocalAddress(),porta_FTP_DTP);                  

            OutputStream data_out=data_sock.getOutputStream();

             RandomAccessFile fileout=new RandomAccessFile(workingPath+"/"+messaggio,"r");

             while((i=fileout.read(buffer))!=-1)

               {

                 data_out.write(buffer,0,i);

                 data_out.flush();

               }

              data_out.close();

             comandiOut.println("226 transfer complete.");

              fileout.close();

              data_sock.close();

           }

           catch(IOException e)

           {

             System.out.println(e);

              System.out.println("Errore durante RETR");

              comandiOut.println("550 file transfer error");

          }

          }

         //procedura remota

          else

         {

           try

           {

             Socket file_sock=new Socket(server_sorgente,Porta_dati);

             String risp=new String();

             Integer porta_file;

             ObjectOutputStream oos2=new ObjectOutputStream(file_sock.getOutputStream());

             ObjectInputStream ois2=new ObjectInputStream(file_sock.getInputStream());

             Socket data_sock=new Socket(connessione.getInetAddress(),remote_port);

          OutputStream data_out=data_sock.getOutputStream();

             oos2.writeObject("richiesta file");

             oos2.flush();

             oos2.writeObject(messaggio);

             oos2.flush();

             risp=(String)ois2.readObject();

             //System.out.println(risp);

             if(risp.equals("trasferimento accordato"))

             {

              porta_file=(Integer)ois2.readObject();

              ServerSocket sock_in_file=new ServerSocket(porta_file.intValue());

              oos2.writeObject("pronto");

              oos2.flush();

              file_sock.close();

              file_sock.close();

              ois2.close();

             oos2.close();

              Socket sock_in_dati=sock_in_file.accept();

              ObjectInputStream ois3=new ObjectInputStream(sock_in_dati.getInputStream());

              System.out.println("trasferimento accordato da "+server_sorgente);

              comandiOut.println("150 Binary data connection.");

              while((i=ois3.read(buffer))!=-1)

              {

                data_out.write(buffer,0,i);

                 data_out.flush();

                }

              data_out.close();

             comandiOut.println("226 transfer complete.");

             System.out.println("trasferimento completato");

             ois3.close();

             }

             else

             {

               System.out.println("Trasferimento non possibile");

               comandiOut.println("550 file transfer error");

               ois2.close();

               oos2.close();

             }

           }

           catch(Exception e)

           {

             System.out.println(e);

             System.out.println("Errore durante RETR");

             comandiOut.println("550 file transfer error");

             //gestisce la procedura per indicare che il server non c'è più

             if(e.getClass().toString().equals("class java.net.ConnectException"))

             {

             try

             {

              Socket sock_com=new Socket(nome_coordinatore,Porta_com);

               ObjectInputStream ois=new ObjectInputStream(sock_com.getInputStream());

               ObjectOutputStream oos=new ObjectOutputStream(sock_com.getOutputStream());

               String mess=new String();

               oos.writeObject("informazione");

               oos.flush();

               oos.writeObject(server_sorgente);

               oos.flush();

               mess=(String)ois.readObject();

               System.out.println(mess);

               oos.close();

               ois.close();

             }

             catch(Exception ex)

             {

              System.out.println("Errore durante l\' invio di informazioni al coordinatore");

              System.out.println(ex);

             }

             }

           }

         }//else(server)

       }//if(trovato)

       else

       {

          System.out.println(nome_utente+": richiesto file inesistente");

          scrittoreLog.write(nome_utente+": richiesto file inesistente\r\n");

          scrittoreLog.flush();

          comandiOut.println("550 file unavailable");

     }//else(trovato)

       }

       catch(FileNotFoundException e)

       {

          System.out.println(nome_utente+": richiesto file inesistente");

          scrittoreLog.write(nome_utente+": richiesto file inesistente\r\n");

          scrittoreLog.flush();

          comandiOut.println("550 file unavailable");

      }

      

       }//fine comando RETR

 

       //COMANDO STOR:

       if(messaggio.startsWith("STOR"))

       {

       String lista_file2[]=new String[60];

          messaggio=messaggio.substring(4);

       messaggio=messaggio.trim();

       comandiOut.println("150 Binary data connection.");

       try

       {

          RandomAccessFile filein=new RandomAccessFile(workingPath+"/"+messaggio,"rw");

          System.out.println("L\' utente "+nome_utente+" invia il file "+messaggio);

          scrittoreLog.write("L\' utente "+nome_utente+" invia il file "+messaggio+"\r\n");

          scrittoreLog.flush();

          Socket data_sock=new Socket(connessione.getInetAddress(),remote_port,connessione.getLocalAddress(),porta_FTP_DTP);

          InputStream data_in=data_sock.getInputStream();

          byte buffer[]=new byte[1024];

          int i;

          try

          {

            while((i=data_in.read(buffer))!=-1)

               {

                 filein.write(buffer,0,i);

               }

            data_in.close();

            comandiOut.println("226 transfer complete.");

            filein.close();

            data_sock.close();

           

            temp_lista=workingPath.list();

            for(int cont=0;(cont<temp_lista.length);cont++)

           {

              if(temp_lista[cont]==null)break;

              lista_file2[cont]=temp_lista[cont];

           }

           //aggiorno la lista in locale

            synchronized(serverReg)

           {

            for(int j=0;j<serverReg.lista_server.length;j++)

                {

                 if(serverReg.lista_server[j]==null)break;

                 if(serverReg.lista_server[j].equals(connessione.getLocalAddress().getHostName()))

                 {

                    serverReg.lista_file_server[j]=lista_file2;

                    break;

                 }

               }

           }//synchro

            //aggiorno il coordinatore

           new Thread(new aggiornaCoordinatore(nome_coordinatore,lista_file2)).start();

           

          }

          catch(Exception e)

          {

            //System.out.println(e);

            System.out.println("Errore durante STOR");

          }

       }

       catch(Exception e)

       {

          System.out.println("Errore nel trasferimento del file.");

          //System.out.println(e);

          comandiOut.println("452 Request action not taken.");

       }

 

       }

 

       //COMANDO APPE: esegue l' append sul file del server se esiste, altrimenti lo crea

       if(messaggio.startsWith("APPE"))

       {

       //Gestire il comando

       comandiOut.println("502 command not implemented.");

       }

 

       //COMANDO ABOR: interruzione o fine del trasferimento di dati, chiusura porta dati

       if(messaggio.startsWith("ABOR"))

       {

       //Gestire il comando

       comandiOut.println("502 command not implemented.  ");

       }

 

       //**********************************************************/

       //GRUPPO DI COMANDI PER LA GESTIONE DEI FILE E DEI DIRETTORI

       //**********************************************************/

      

       //COMANDO DELE: cancella un file

       if(messaggio.startsWith("DELE"))

       {

       String temp_lista2[]=new String[60];

       messaggio=messaggio.substring(4);

       messaggio=messaggio.trim();

       try

       {

          File f=new File(workingPath,messaggio);

          if(f.exists())

          {

            if(f.delete())

            {

               System.out.println("File "+messaggio+" cancellato dall\' utente "+nome_utente);

               scrittoreLog.write("File "+messaggio+" cancellato dall\' utente "+nome_utente+"\r\n");

               comandiOut.println("250 Sussection: file deleted.");

              

               temp_lista2=workingPath.list();

               for(int i=0;i<temp_lista2.length;i++)

               {

                 if(temp_lista2[i]==null)break;

                 lista_file[i]=temp_lista2[i];

               }

               //aggiorno la lista in locale

               synchronized(serverReg)

              {

               for(int j=0;j<serverReg.lista_server.length;j++)

                 {

                 if(serverReg.lista_server[j]==null)break;

                 if(serverReg.lista_server[j].equals(connessione.getLocalAddress().getHostName()))

                 {

                    serverReg.lista_file_server[j]=lista_file;

                    break;

                 }

                }

               }//synchro

              

               //aggiorno il coordinatore

              new Thread(new aggiornaCoordinatore(nome_coordinatore,lista_file)).start();

              

            }

            else

            {

               System.out.println("Impossibile cancellare il file "+messaggio+" richiesto dall\' utente "+nome_utente);

               scrittoreLog.write("Impossibile cancellare il file "+messaggio+" richiesto dall\' utente "+nome_utente+"\r\n");

               comandiOut.println("550 File unavailable or remote.");

            }

          }

          else

          {

            comandiOut.println("550 File unavailable or remote.");

          }

       }

       catch(NullPointerException e)

       {

          System.out.println("L\' utente "+nome_utente+" non ha inserito il nome del file");

          comandiOut.println("501 Syntax error in parameters or arguments.");

       }

      

       }

 

       //COMANDO LIST: visualizza il contenuto della directory

       if(messaggio.startsWith("LIST")||messaggio.startsWith("NLST"))

       {

       try

       {

          Socket list_sock=new Socket(connessione.getInetAddress(),remote_port,connessione.getLocalAddress(),porta_FTP_DTP);

          comandiOut.println("150 ASCII data");

          scrittoreLog.write("L\' utente "+nome_utente+": richiesta lista dei file della directory "+workingPath+"\r\n");

          System.out.println("L\' utente "+nome_utente+": richiesta lista dei file della directory "+workingPath);

          PrintWriter list_out=new PrintWriter(list_sock.getOutputStream(),true);

          //list_out.println("Contents of "+workingPath);

          list_out.println("Files available:");

          lista_file=workingPath.list();

          //lista file locali e remoti

          for(int yy=0;yy<lista_file.length;yy++)

          {

            if(lista_file[yy]==null)break;

            list_out.println("-lc- "+lista_file[yy]);

          }

          synchronized(serverReg)

          {

         for(int j=0;j<serverReg.lista_server.length;j++)

            {

            if(serverReg.lista_server[j]==null)break;

            for(int i=0;i<serverReg.lista_file_server[j].length;i++)

              {

              if(serverReg.lista_file_server[j][i]==null)break;

              if(serverReg.lista_server[j].equals(connessione.getLocalAddress().getHostName()))

              {

                 //list_out.println("-lc- "+serverReg.lista_file_server[j][i]);

              }

              else

              {

                 list_out.println("-rm- "+serverReg.lista_file_server[j][i]);

              }

              }

            }

          }//synchro

            //System.out.println("Fine lista file");

 

        

         list_out.close();

         comandiOut.println("226 Transfer complete.");

         }

       catch(Exception e)

       {

          System.out.println(e);

          comandiOut.println("450 Requested file action not taken.");

       }

       }

 

       //COMANDO PWD: visualizza la directory corrente sul server

       if(messaggio.startsWith("PWD"))

       {

       //Gestire il comando

       comandiOut.println("502 command not implemented.");

       }

 

       //COMANDO CDUP: passare alla directory superiore

       if(messaggio.startsWith("CDUP"))

       {

       //Gestire il comando

       comandiOut.println("502 command not implemented.");

       }

 

       //COMANDO CWD: cambiare la directory corrente

       if(messaggio.startsWith("CWD"))

       {

       //Gestire il comando

       comandiOut.println("502 command not implemented.");

       }

 

       //COMANDO RNFR: cambia il nome del file da ... (viene seguito da RNTO)

       if(messaggio.startsWith("RNFR"))

       {

       //Gestire il comando

       comandiOut.println("502 command not implemented.");

       }

 

       //COMANDO RNTO: cambia il nome del file in ...

      if(messaggio.startsWith("RNTO"))

       {

       //Gestire il comando

       comandiOut.println("502 command not implemented.");

       }

 

       //COMANDO RMD: rimuove la directory specificata

       if(messaggio.startsWith("RMD"))

       {

       //Gestire il comando

       comandiOut.println("502 command not implemented.");

       }

      

       //COMANDO MKD: crea la directory specificata

       if(messaggio.startsWith("MKD"))

       {

       //Gestire il comando

       comandiOut.println("502 command not implemented.");

       }

     

      

      }

 

      //CHIUSURA DELLA CONNESSIONE

      comandiOut.println("221 Arrivederci! Comunicazione terminata.\r\n");

      scrittoreLog.write(client_remoto+": invio messaggio di chiusura\r\n");

      scrittoreLog.flush();

      connessione.close();

      scrittoreLog.close();

      System.out.println("Connessione chiusa con "+client_remoto);

      

     }

     catch(IOException e)

     {System.err.println(e);}

  }

 

  public void registraUtenti()

  {

     try

    {

     FileOutputStream out = new FileOutputStream("iscritti.dat",false);

     ObjectOutputStream oos = new ObjectOutputStream(out);

     try

     {

        oos.writeObject(new Iscritto("simone","simone"));

        oos.writeObject(new Iscritto("anonimo","ftp"));

        oos.writeObject(new Iscritto("psimon","psimon"));

        oos.flush();

        oos.close();

        out.close();

      }

      catch(IOException e)

      {

        System.err.println(e);

      }

     }

     catch(Exception e)

     {

     }

  }

 

  public boolean leggi(Iscritto iscr)

{

  boolean trovato=false;

  try

  {

     FileInputStream in = new FileInputStream("iscritti.dat");

     ObjectInputStream ois = new ObjectInputStream(in);

   try

   {

    while(true)

     {   

        Iscritto i = (Iscritto) ois.readObject();

        if(i.equals(iscr)) {trovato=true;break;}

       }

      ois.close();

      in.close();

   }

   catch(IOException ee)

   {

    if(!ee.getClass().toString().equals("class java.io.EOFException"))

    {

       System.out.println(ee);

    }

   }

   catch(Exception e)

   {

      System.out.println(e);

   }

  }

  catch(Exception e)

  {

  }

  return trovato;

}

 

}