//---------------------------------------------------------------------------
// Copyright (C) 2001 Dallas Semiconductor Corporation, All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// Except as contained in this notice, the name of Dallas Semiconductor
// shall not be used except as stated in the Dallas Semiconductor
// Branding Policy.
//--------------------------------------------------------------------------
//
//  jibload.c - Load a JiBLet to the Java-powered iButton(s) found on
//              the 1-Wire
//
//  version 3.00 Beta
//

#include "jib96.h"
#include "ownet.h"
#include <string.h>

#define MAXDEVICES 10

// external functions
extern SMALLINT  FindDevices(int,uchar FamilySN[][8],SMALLINT,int);
extern void      PrintSerialNum(uchar*);

// local prototypes
void LoadJiB(int portnum, uchar *dev, char *filename,
             int MasterEraseFirst, int ClearLoadPINMode);
int ProcessCommandLine(int p_ArgC, char **p_lpArgV,
                       uchar *MasterEraseFirst, uchar *ClearLoadPINMode);
uint GetFileToLoad(char *p_FileName, uchar *p_FileBuffer, uint p_Len);


//--------------------------------------------------------------------------
// Main to load a JiBlet into a JiB
//
int main(int argc, char *argv[])
{
   uchar  MasterEraseFirst  = FALSE;
   uchar  ClearLoadPINMode    = FALSE;
   int    i, portnum=0,NumDevices;
   uchar  FamilySN[MAXDEVICES][8];

   printf("\nLoadJiB version 3.00B\n\n");

   // see if another port is desired
   if ((argc < 3) ||
       (!ProcessCommandLine(argc,argv,&MasterEraseFirst,&ClearLoadPINMode)))
   {
      printf("\nUsage: LoadJiB port filename [-e] [-l] [-h]\n");
      printf("       port: required port name\n");
      printf("       filename: filename of JiBlet to load\n");
      printf("       -e: Master erase first\n");
      printf("       -l: Clear Load PIN mode\n");
      printf("       -h: Display usage\n\n");
      exit(0);
   }

   // attempt to acquire the 1-Wire Net
   if ((portnum = owAcquireEx(argv[1])) < 0)
   {
      OWERROR_DUMP(stdout);
      exit(1);
   }

   // success
   printf("Port opened: %s\n",argv[1]);

   // Find the device(s)
   NumDevices = FindDevices(portnum, &FamilySN[0], 0x16, MAXDEVICES);

   if (NumDevices > 0)
   {
      printf("\n");
      printf("JiB(s) Found: \n");
      for (i = 0; i < NumDevices; i++)
      {
         PrintSerialNum(FamilySN[i]);
         printf("\n");
      }
      printf("\n\n");

      // loop through the devices and do a test on each
      for (i = 0; i < NumDevices; i++)
        LoadJiB(portnum, FamilySN[i], argv[2],
                MasterEraseFirst, ClearLoadPINMode);
   }
   else
      printf("No JiB's Found!\n");

   // release the 1-Wire Net
   owRelease(portnum);
   printf("Closing port %s.\n", argv[1]);
   exit(0);
   return 0;

}

//--------------------------------------------------------------------------
// Check command parameters for flags
//
int ProcessCommandLine(int p_ArgC, char **p_lpArgV,
                       uchar *MasterEraseFirst, uchar *ClearLoadPINMode)
{
   int l_i;

   // start looking at parameters after the two required ones
   for(l_i = 3;  l_i < p_ArgC; l_i++)
   {
      // check for flag designator
      if((p_lpArgV[l_i][0] == '/')||(p_lpArgV[l_i][0] == '-'))
      {
         // master erase first?
         if ((p_lpArgV[l_i][1] == 'e') || (p_lpArgV[l_i][1] == 'E'))
            *MasterEraseFirst = TRUE;

         // clear load pin to use signatures
         if ((p_lpArgV[l_i][1] == 'l') || (p_lpArgV[l_i][1] == 'L'))
            *ClearLoadPINMode = TRUE;

         // usage request
         if ((p_lpArgV[l_i][1] == 'h') || (p_lpArgV[l_i][1] == 'H'))
            return FALSE;
      }
   }

   return TRUE;
}

//--------------------------------------------------------------------------
// Read the file into the supplied buffer.
//
uint GetFileToLoad(char *p_FileName, uchar *p_FileBuffer, uint p_Len)
{
  FILE  *l_InFile;
  uint l_BytesRead = 0,
        l_ReadSize = 0;

  if(!(l_InFile = fopen(p_FileName,"r+b")))
  {
    perror("Couldn't open file");
    return FALSE;
  }


  while((l_ReadSize = fread(p_FileBuffer+l_BytesRead, 1, p_Len-l_BytesRead, l_InFile)) > 0)
  {
    l_BytesRead += l_ReadSize;
  }

  fclose(l_InFile);

  return l_BytesRead;
}

//--------------------------------------------------------------------------
// Load the jib files into the iButton
//
void LoadJiB(int portnum, uchar *dev, char *filename,
             int MasterEraseFirst, int ClearLoadPINMode)
{
   LPRESPONSEAPDU l_lpResponseAPDU;
   uchar          l_FileName[260],
                  l_FileBuff[4096];
   AID            l_CurrentAID;
   uint          filelen;

   // select the device and put in overdrive
   printf("Device: ");
   PrintSerialNum(dev);
   printf("\n");

   owSerialNum(portnum,dev,0);
   if (!owOverdriveAccess(portnum))
      printf("ERROR, could not get device in overdrive!\n");

   // make sure there is time for hashing and a signature verification
   SetDefaultExecTime(800);

   if (MasterEraseFirst)
   {
      printf("Master Erasing Button: ");
      l_lpResponseAPDU = MasterErase(portnum);

      if(l_lpResponseAPDU->SW != ERR_ISO_NORMAL_00)
         printf("\nMaster Erase Failed with SW = 0x%04hX\n",l_lpResponseAPDU->SW);
      else
         printf("OK\n");
   }

   if (ClearLoadPINMode)
   {
      printf("Clearing Load By PIN: ");
      l_lpResponseAPDU = SetLoadPINMode(portnum,0);

      if(l_lpResponseAPDU->SW != ERR_ISO_NORMAL_00)
         printf("\nClear Load PIN Mode Failed with SW = 0x%04hX\n",l_lpResponseAPDU->SW);
      else
         printf("OK\n");
   }

   printf("Loading %s: ",filename);

   // read the file and load if found
   filelen = GetFileToLoad(filename,l_FileBuff,sizeof(l_FileBuff));
   if (filelen > 0)
   {
      // assume the filename less extension is the AID
      l_CurrentAID.Len = strlen(filename) - strlen(".jib");
      // unless, of course, that's too large
      if(l_CurrentAID.Len>MAX_AID_SIZE)
         l_CurrentAID.Len = MAX_AID_SIZE;
      memcpy(l_CurrentAID.Data, filename, l_CurrentAID.Len);

      l_lpResponseAPDU = LoadApplet(portnum, l_FileBuff, filelen ,&l_CurrentAID);

      if(l_lpResponseAPDU->SW != ERR_ISO_NORMAL_00)
      {
         strncpy((char *)l_FileName, filename, l_CurrentAID.Len);
         l_FileName[l_CurrentAID.Len] = 0;
         printf("\nLoad of %s Failed with SW = 0x%04hX\n",l_FileName,l_lpResponseAPDU->SW);
      }
      else
         printf("OK\n");
   }
   else
      printf("\nFile %s failed to open.\n",filename);
}
