/* 
 * File:   Eszkoz.java
 * Szerzo: Ondi Attila (att@ludens.elte.hu)
 * Leiras: Ezen osztaly segiitsegevel lehet kenyelmesen
 *         kommunikalni az elektronikus-penztarca alkalmazassal
 */

import java.util.*;
import javax.comm.*;
import java.smartcard.*;
import com.iButton.ifd.dallasIFD.DallasIFDDriver;

/*
 * a gyuruvel kommunikalo osztaly
 */
public class Eszkoz implements SmartCardListener
{
   protected final static int userJELSZOHOSSZ = 8;
   protected final static int bankJELSZOHOSSZ = 8;

   /* Az alabbi konstansok az eszkozzel valo kommunikaciohoz kellenek */

   protected final static byte EA_CLA               = (byte) 0x81;
   protected final static byte EA_EgyenlegKerdez    = (byte) 0x01;
   protected final static byte EA_EgyenlegModosit   = (byte) 0x03;
   protected final static byte EA_LimitKerdez       = (byte) 0x04;
   protected final static byte EA_LimitModosit      = (byte) 0x05;
   protected final static byte EA_JelszoHasonlit    = (byte) 0x06;
   protected final static byte EA_JelszoModosit     = (byte) 0x07;
   protected final static byte EA_TranzakcioKerdez  = (byte) 0x08;
   protected final static byte SELECT_CLA           = (byte) 0x00;
   protected final static byte SELECT_INS           = (byte) 0xA4;
   protected final static int SELECT_P1             = (int) 0x04;
   protected final static int SELECT_P2             = (int) 0x00;
   protected final static int SW_NO_ERROR           = (int) 0x9000;
   protected final static int SW_UNKNOWN            = (int) 0x6F00;

   protected Slot slot;
   protected Channel channel;
   protected DallasIFDDriver driver;
   protected boolean eszkozJelen, /* jelen van-e a gyuru */
                     appletJelen; /* a gyurun megvan-e a megfelelo alkalmazas */

/* ---------------------------------------- */

   public Eszkoz()
   {
      startPolling(null);
   }

   /* 
    * jelen van-e a gyuru 
    */
   public boolean eszkozJelen()
   {
      return eszkozJelen;
   }

   /* 
    * a gyurun megtalalhato-e a megfelelo alkalmazas
    */
   public boolean appletJelen()
   {
      return(appletJelen = hasApplet("EszkozApplet"));
   }

   /*
    * a csatolofelulet azonositoja 
    */
   public String getAdapterID()
   {
      String idString = new String("");
      int[] adapterID = driver.getAdapterId();

      if(adapterID != null)
      {
         for(int i=0; i<adapterID.length; i++)
         {
            if(adapterID[i]<10)
            {
               idString += '0';
               idString += Integer.toHexString(adapterID[i]).toUpperCase();
            }
            else
            {
               idString += Integer.toHexString(adapterID[i]).toUpperCase();
            }
         }
      }
      return idString;
   }

   /*
    * a gyuru azonositoja 
    */
   public String getiButtonID()
   {
      String idString = new String("");
      int[] buttonID = driver.getiButtonId();

      if(buttonID != null)
      {
         for(int i=0; i<buttonID.length; i++)
         {
            if(buttonID[i]<10)
            {
               idString += '0';
               idString += Integer.toHexString(buttonID[i]).toUpperCase();
            }
            else
            {
               idString += Integer.toHexString(buttonID[i]).toUpperCase();
            }
         }
      }
      return idString;
   }

   /*
    * behelyeztek a csatolofeluletbe a gyurut
    * (SmartCradListener metodus)
    */
   public void cardInserted(SmartCardEvent evt)
   {
      System.out.println("Java iButton-t megtal\u00e1ltam");
      slot = evt.getSlot();
      try
      {
         channel = slot.openChannel();
         driver = (DallasIFDDriver)channel.getIFD();
         eszkozJelen = true;
      }
      catch(IFDException e)
      {
         System.out.println("Kiv\u00e9tel (IFDException): "+e.getMessage());
         System.out.println("Behelyez\u00e9si hiba (Insertion error): "+
                            "Ha csatlakoztatva van, vedd le, \u00e9s helyezd be "+
                            "\u00fajra az iButton-t");
         slot = null;
         e.printStackTrace();
      }
      catch(InvalidChannelException e)
      {
         System.out.println("Kiv\u00e9tel (InvalidChannelException): "+
                             e.getMessage());
         slot = null;
         e.printStackTrace();
      }
      catch(SmartCardException e)
      {
         System.out.println("Kiv\u00e9tel (SmartCardException): "+e.getMessage());
         System.out.println("Behelyez\u00e9si hiba (Insertion error): "+
                            "Ha csatlakoztatva van, vedd le, \u00e9s helyezd be"+
                            " \u00fajra az iButton-t");
         slot = null;
         e.printStackTrace();
      }
   }

   /*
    * kivettek a csatolofeluletbol a gyurut
    * (SmartCradListener metodus)
    */
   public void cardRemoved(SmartCardEvent evt)
   {
      System.out.println("Java iButton lev\u00e9ve");
      eszkozJelen = false;
      appletJelen = false;
      try
      {
         channel.close();
      }
      catch (IFDException e)
      {
         System.out.println("Kiv\u00e9tel (IFDException): "+e.getMessage());
         e.printStackTrace();
      }
      catch (InvalidChannelException e)
      {
         System.out.println("Kiv\u00e9tel (InvalidChannelException): "+
                             e.getMessage());
         e.printStackTrace();
      }
      slot = null;
      driver = null;
   }

   /* 
    * tovabbi (itt nem hasznalt) SmartCardListener metodusok
    */
   public void unsolicitedAPDU(SmartCardEvent evt)
   {
   }

   public void cardReset(SmartCardEvent evt)
   {
   }

   public void extendedEvent(SmartCardEvent evt)
   {
   }

   /*
    * a visszatero APDU valasz hibat jelez-e
    */
   private void validateResponseData(ResponseAPDU response) 
                   throws EszkozException
   {
      if (response.getSW() != SW_NO_ERROR)
      {
         System.out.println("validate error: "+response.getSW());
         System.out.println("SW_NO_ERROR:    "+SW_NO_ERROR);
         throw new EszkozException();
      }
   }

   /**
    * Ha a bedugott iButton megfelelo appletet tartalmaz, 
    * akkor igazzal ter vissza, kulonben hamis.
    */
   public boolean hasApplet(String appletName)
   {
      try
      {
         char[] appletNameChars = appletName.toCharArray();
         byte[] buffer = new byte[appletName.length()];

         for (int i = 0; i < buffer.length; i++)
         {
            buffer[i] = (byte) appletNameChars[i];
         }
         CommandAPDU appletAPDU = 
            new CommandAPDU((byte)SELECT_CLA, (byte)SELECT_INS, (byte)SELECT_P1,
                            (byte)SELECT_P2, buffer, (byte)0);
         ResponseAPDU response = channel.sendAPDU(appletAPDU);
         return(response.getSW() == SW_NO_ERROR);
      }
      catch  (SmartCardException  e)
      {
         System.out.println("APDU hiba (APDU error)");
         System.out.println("Kiv\u00e9tel (Exception): "+e.getMessage());
         e.printStackTrace();
      }
      return false;
   }

   /* a soros es parhuzamos portok figyelese */
   protected void startPolling(String nativeDevString)
   {
      /* Parhozamos port figyelese */
      addPort("LPT", "PORT_TYPE_LEGACY_PARALLEL", true);

      /* az alabbiak a soros porti cstolofelulethez kellenek */
/*      if (nativeDevString == null)
      {
         try
         {
            Enumeration allPorts = CommPortIdentifier.getPortIdentifiers();
            CommPortIdentifier portId;
            while (allPorts.hasMoreElements())
            {
               // A portok vegigjarasa 
               portId = (CommPortIdentifier) allPorts.nextElement();
               if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL)
               {
               	addPort(portId.getName(), "PORT_TYPE_SERIAL", false);
               }
            }
         }
         catch (Throwable t)
         {
         }
      }
      else
      {
         // A meglevo kodot hasznaljuk a soros kommunikaciohoz 
         addPort(nativeDevString, "PORT_TYPE_LEGACY_SERIAL", false);
      }
   }
*/
}

   /* 
    * port hozzaadasa a figyeleshez 
    */
   protected void addPort(String portName, String portType, boolean firstPort)
   {
      IFDDriver dallasIFD = new DallasIFDDriver();
      Properties properties = new Properties();
      properties.put(dallasIFD.getClass().getName() + ".Port_Name", portName);
      properties.put(dallasIFD.getClass().getName() + ".Port_Type", portType);
      try
      {
         dallasIFD.setConfiguration(properties);
         IFDRegistry reg = IFDRegistry.getDefaultRegistry();
         reg.addIFD(dallasIFD);
         if (firstPort)
         {
            reg.addSmartCardListener(this);
         }
      }
      catch  (IFDException e)
      {
         System.out.println("Kiv\u00e9tel (Exception): "+e.getMessage());
         e.printStackTrace();
      }
   }

/* 
 * ------------------------------------- 
 * A kommunikaciot megvalosito metodusok
 * -------------------------------------
 */

   /* 
    * byte[] -bol Integer-t keszit
    */
   protected int BytesToInteger(byte[] b)
   {
      int szam=0;

      szam+=(int)b[0];
      for(byte i=1;i<4;i++)
      {
         szam<<=8;
         if((int)b[i]<0)
         {
            szam+=(int)b[i]+256;
         }
         else
         {
            szam+=(int)b[i];
         }
      }
      return szam;
   }

   /* 
    * Integer-bol byte[] -ot keszit
    */
   protected byte[] IntegerToBytes(int szam)
   {
      byte[] b = new byte[4];

      for(byte i=3;i>=0;i--)
      {
         b[i]=(byte)szam;
         szam>>>=8;
      }
      return b;
   }

   /*
    * az egyenleg lekerdezese
    */
   public int egyenlegKerdez()
   {
      byte[] buffer = new byte[0];
      CommandAPDU appletAPDU;
      ResponseAPDU response;

      try
      {
         appletAPDU = 
            new CommandAPDU(EA_CLA, EA_EgyenlegKerdez, (byte)0, (byte)0, buffer,
                            (byte)0);
         response = channel.sendAPDU(appletAPDU);
         validateResponseData(response);

         return BytesToInteger(response.getDataBytes());
      }
      catch(SmartCardException e)
      {
         System.out.println("SmartCardException");
      }
      catch(EszkozException e)
      {
         System.out.println("EszkozException");
      }
      return -1;
   }

   /* 
    * egyenlegmodositas
    */
   public boolean egyenlegModosit(boolean bank, String Jelszo, int mennyivel)
   {
      byte[] buffer = new byte[2+Jelszo.length()+4];
      byte[] buffer1 = Jelszo.getBytes();
      byte[] buffer2 = IntegerToBytes(mennyivel);
      CommandAPDU appletAPDU;
      ResponseAPDU response;

      /* banki tranzakcio */
      if(bank)
      {
         buffer[0] = 1;
         buffer1 = bankKodol(buffer1);
      }
      else /* bolti tranzakcio */
      {
         buffer[0] = 0;
         buffer1 = userKodol(buffer1);
      }
      buffer[1] = (byte)buffer1.length;
      for(int i = 0;i<buffer1.length;i++)
      {
         buffer[i+2] = buffer1[i];
      }
      for(int i = 0;i<4;i++)
      {
         buffer[i+2+buffer1.length] = buffer2[i];
      }
      try
      {
         appletAPDU = 
            new CommandAPDU(EA_CLA, EA_EgyenlegModosit, (byte)0, (byte)0, 
                            buffer, (byte)0);
         response = channel.sendAPDU(appletAPDU);
         validateResponseData(response);
         return(response.getDataBytes()[0]==1);
      }
      catch(SmartCardException e)
      {
      }
      catch(EszkozException e)
      {
      }
      return false;
   }

   /*
    * limit lekerdezese
    */
   public int limitKerdez()
   {
      byte[] buffer = new byte[0];
      CommandAPDU appletAPDU;
      ResponseAPDU response;

      try
      {
         appletAPDU = 
            new CommandAPDU(EA_CLA, EA_LimitKerdez, (byte)0, (byte)0, buffer, 
                            (byte)0);
         response = channel.sendAPDU(appletAPDU);
         validateResponseData(response);

         return BytesToInteger(response.getDataBytes());
      }
      catch(SmartCardException e)
      {
      }
      catch(EszkozException e)
      {
      }
      return -1;
   }

   /* 
    * limit modositasa 
    */
   public boolean limitModosit(String bankjelszo, int mennyire)
   {
      byte[] buffer = new byte[2+bankjelszo.length()+4];
      byte[] buffer1 = bankjelszo.getBytes();
      byte[] buffer2 = IntegerToBytes(mennyire);
      CommandAPDU appletAPDU;
      ResponseAPDU response;

      buffer1 = bankKodol(buffer1);
      buffer[1] = (byte)buffer1.length;
      for(int i = 0;i<buffer1.length;i++)
      {
         buffer[i+2] = buffer1[i];
      }
      for(int i = 0;i<4;i++)
      {
         buffer[i+2+buffer1.length] = buffer2[i];
      }
      try
      {
         appletAPDU = 
            new CommandAPDU(EA_CLA, EA_LimitModosit, (byte)0, (byte)0, buffer, 
                            (byte) 0);
         response = channel.sendAPDU(appletAPDU);
         validateResponseData(response);
         return(response.getDataBytes()[0]==1);
      }
      catch(SmartCardException e)
      {
      }
      catch(EszkozException e)
      {
      }
      return false;
   }

   /* 
    * a megadott leszo osszehasonlitasa a gyurun levovel 
    */
   public boolean jelszoHasonlit(String Jelszo) 
   {
      byte[] buffer = new byte[1+Jelszo.length()];
      byte[] buffer1 = userKodol(Jelszo.getBytes());
      CommandAPDU appletAPDU;
      ResponseAPDU response;

      buffer[0] = (byte)Jelszo.length();
      for(int i = 0;i<buffer1.length;i++)
      {
         buffer[i+1] = buffer1[i];
      }
      try
      {
         appletAPDU = 
            new CommandAPDU(EA_CLA, EA_JelszoHasonlit, (byte)0, (byte)0, buffer,
                            (byte)0);
         response = channel.sendAPDU(appletAPDU);
/*
         System.out.print("buffer:   ");
         for(int i=0;i<buffer.length;i++)
         {
            System.out.print(buffer[i]+",");
         }
         System.out.println();
         System.out.print("response: ");
         for(int i=0;i<response.getDataBytes().length;i++)
         {
            System.out.print(response.getDataBytes()[i]+",");
         }
         System.out.println();
*/         
         validateResponseData(response);
         return(response.getDataBytes()[0]==1);
      }
      catch(SmartCardException e)
      {
      }
      catch(EszkozException e)
      {
      }
      return false;
   }
  
   /* 
    * a gyurun levo jelszo megvaltoztatasa
    */
   public boolean jelszoModosit(String bankjelszo, String ujJelszo)
   {
      byte[] buffer = new byte[1+bankjelszo.length()+1+ujJelszo.length()];
      byte[] buffer1 = bankjelszo.getBytes();
      byte[] buffer2 = ujJelszo.getBytes();
      CommandAPDU appletAPDU;
      ResponseAPDU response;

      buffer1 = bankKodol(buffer1);
      buffer2 = userKodol(buffer2);
      buffer[0] = (byte)buffer1.length;
      for(int i = 0;i<buffer1.length;i++)
      {
         buffer[i+1] = buffer1[i];
      }
      buffer[1+buffer1.length] = (byte)buffer2.length;
      for(int i = 0;i<buffer2.length;i++)
      {
         buffer[i+2+buffer1.length] = buffer2[i];
      }
      try
      {
         appletAPDU = 
            new CommandAPDU(EA_CLA, EA_JelszoModosit, (byte)0, (byte)0, buffer,
                            (byte)0);
         response = channel.sendAPDU(appletAPDU);
         validateResponseData(response);
         return(response.getDataBytes()[0]==1);
      }
      catch(SmartCardException e)
      {
      }
      catch(EszkozException e)
      {
      }
      return false;
   }
   /*
    *  agyurun eltarolt tranzakciok kozul az egyyik lekerdezese 
    */
   public byte[] TranzakcioKerdez(String bankjelszo, byte hanyadik)
   {
      byte[] buffer = new byte[1+bankjelszo.length()];
      byte[] buffer1 = bankjelszo.getBytes();
      CommandAPDU appletAPDU;
      ResponseAPDU response;

      buffer1 = bankKodol(buffer1);
      buffer[0] = (byte)buffer1.length;
      for(int i = 0;i<buffer1.length;i++)
      {
         buffer[i+1] = buffer1[i];
      }
      buffer[1+buffer1.length] = hanyadik;
      try
      {
         appletAPDU = 
            new CommandAPDU(EA_CLA, EA_TranzakcioKerdez, (byte)0, (byte)0, 
                            buffer, (byte)0);
         response = channel.sendAPDU(appletAPDU);
         validateResponseData(response);
         return(response.getDataBytes());
      }
      catch(SmartCardException e)
      {
      }
      catch(EszkozException e)
      {
      }
      byte[] b = {0};
      return b;
   }

   /*
    * a felhasznaloi jelszo elkodolasa
    */
   private byte[] userKodol(byte[] kodszo)
   {
      byte[] kodolt = new byte[kodszo.length];
      int hossz = 0;
      
      if(kodszo.length>userJELSZOHOSSZ)
      {
         hossz = userJELSZOHOSSZ;
      }
      else
      {
         hossz = kodszo.length;
      }
      for(int i = 0;i<hossz;i++)
      {
         if(kodszo[i]!=255)
         {
            kodolt[i] = (byte)(kodszo[i]+1);
         }
         else
         {
            kodolt[i] = (byte)0;
         }
      }
      return kodolt;
   }

   /*
    * a banki jelszo elkodolasa
    */
   private byte[] bankKodol(byte[] kodszo)
   {
      byte[] kodolt = new byte[kodszo.length];
      
      int hossz = 0;
      
      if(kodszo.length>bankJELSZOHOSSZ)
      {
         hossz = bankJELSZOHOSSZ;
      }
      else
      {
         hossz = kodszo.length;
      }
      for(int i = 0;i<hossz;i++)
      {
         if(kodszo[i]!=0)
         {
            kodolt[i] = (byte)(kodszo[i]-1);
         }
         else
         {
            kodolt[i] = (byte)255;
         }
      }
      return kodolt;
   }
}