#define NAME         "xadUnDisk"
#define DISTRIBUTION "(Freeware) "
#define REVISION     "0"

/* Programmheader

	Name:		xadUnDisk
	Author:		SDI
	Distribution:	Freeware
	Description:	dearchives disk archives
	Compileropts:	-
	Linkeropts:	-gsi -l amiga

 1.0   18.11.98 : first version
*/

#include <proto/xadmaster.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <exec/memory.h>
#include <dos/dosasl.h>
#include <utility/hooks.h>
#include "SDI_defines.h"
#include "SDI_compiler.h"
#define SDI_TO_ANSI
#include "SDI_ASM_STD_protos.h"

#ifdef __SASC
  #define xadmasterbase	 xadMasterBase 
  #define ASSIGN_XAD
#else
  struct xadMasterBase * xadMasterBase = 0;
  #define ASSIGN_XAD	 xadMasterBase = xadmasterbase;
#endif
struct DosLibrary *	 DOSBase = 0;
struct ExecBase *	 SysBase  = 0;

#define PARAM	"FROM/A,TO,LOWCYL/N,HIGHCYL/N,ENTRY/N,PASSWORD,"	\
		"NE=NOEXTERN/S,INFO=LIST/S,SHOWTEXTS/S,OW=OVERWRITE/S,"	\
		"IG=IGNOREGEOMETRY/S"

struct Args {
  STRPTR from;
  STRPTR to;
  LONG * lowcyl;
  LONG * highcyl;
  LONG * entry;
  STRPTR password;
  ULONG  noextern;
  ULONG  info;
  ULONG  showtexts;
  ULONG  overwrite;
  ULONG  ignoregeometry;
};

ASM(ULONG) SAVEDS progrhook(REG(a0, struct Hook *),
  REG(a1, struct xadProgressInfo *));
struct Hook prhook = {{0,0},(ULONG (*)()) progrhook, 0, 0};

ULONG start(void)
{
  ULONG ret = RETURN_FAIL;
  struct DosLibrary *dosbase;

  SysBase = (*((struct ExecBase **) 4));
  { /* test for WB and reply startup-message */
    struct Process *task;
    if(!(task = (struct Process *) FindTask(0))->pr_CLI)
    {
      WaitPort(&task->pr_MsgPort);
      Forbid();
      ReplyMsg(GetMsg(&task->pr_MsgPort));
      return RETURN_FAIL;
    }
  }

  if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  {
    LONG err = 0;
    struct xadMasterBase *xadmasterbase;

    DOSBase = dosbase;
    if((xadmasterbase = (struct xadMasterBase *)
    OpenLibrary("xadmaster.library", 1)))
    {
      LONG def = 1;
      struct Args args;
      struct RDArgs *rda;
      
      memset(&args, 0 , sizeof(struct Args));
      args.entry = &def;

      ASSIGN_XAD
      if((rda = ReadArgs(PARAM, (LONG *) &args, 0)))
      {
	if(args.to || args.info)
	{
	  struct xadArchiveInfo *ai;
	
	  if((ai = (struct xadArchiveInfo *)
	  xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
	  {
	    if(!(err = xadGetInfo(ai, XAD_INFILENAME, args.from,
	    XAD_NOEXTERN, args.noextern, args.password ? XAD_PASSWORD :
	    TAG_IGNORE, args.password, TAG_DONE)))
	    {
	      if(args.info)
	      {
	        struct xadDiskInfo *xdi;
	        Printf("ArchiverName:   %s\n", ai->xai_Client->xc_ArchiverName);
#ifdef DEBUG
	        Printf("Password:       %s\n", ai->xai_Password ? ai->xai_Password : "<none>");
	        Printf("InSize:         %ld\n", ai->xai_InSize);
	        Printf("InPos:          %ld\n", ai->xai_InPos);
#endif

	        xdi = ai->xai_DiskInfo;
	        while(xdi)
	        {
		  if(xdi->xdi_EntryNumber != 1 || xdi->xdi_Next)
	            Printf("\nEntry:          %ld\n", xdi->xdi_EntryNumber);
	          Printf("EntryInfo:      %s\n", xdi->xdi_EntryInfo ? xdi->xdi_EntryInfo : "<none>");
#ifdef DEBUG
	          Printf("Flags:          ");
	          if(xdi->xdi_Flags & XADDIF_CRYPTED)
	            Printf("XADDIF_CRYPTED ");
	          if(xdi->xdi_Flags & XADDIF_INFOTEXT)
	            Printf("XADDIF_INFOTEXT ");
	          if(xdi->xdi_Flags & XADDIF_BANNER)
	            Printf("XADDIF_BANNER ");
	          Printf(xdi->xdi_Flags ? "\n" : "<none>\n");
#endif
	          Printf("SectorSize:     %ld\n", xdi->xdi_SectorSize);
	          Printf("Sectors:        %ld\n", xdi->xdi_TotalSectors);
	          Printf("Cylinders:      %ld\n", xdi->xdi_Cylinders);
	          Printf("CylSectors:     %ld\n", xdi->xdi_CylSectors);
	          Printf("Heads:          %ld\n", xdi->xdi_Heads);
	          Printf("TrackSectors:   %ld\n", xdi->xdi_TrackSectors);
	          Printf("LowCyl:         %ld\n", xdi->xdi_LowCyl);
	          Printf("HighCyl:        %ld\n", xdi->xdi_HighCyl);
	          if(xdi->xdi_Flags & XADDIF_INFOTEXT)
	            Printf("There is an InfoText with size %ld.\n", xdi->xdi_InfoTextSize);
	          if(xdi->xdi_Flags & XADDIF_BANNER)
	            Printf("There is a Banner with size %ld.\n", xdi->xdi_BannerSize);
	          if(xdi->xdi_Flags & XADDIF_CRYPTED)
	            Printf("The entry is encrypted\n");
	          xdi = xdi->xdi_Next;
	        }
	        ret = 0;
	      }
	      else
	      {
		struct xadDeviceInfo *dvi = 0;

	        if(args.to[strlen(args.to)-1] == ':')
	        {
	          if((dvi = (struct xadDeviceInfo *)
	          xadAllocObjectA(XADOBJ_DEVICEINFO, 0)))
	          {
	            args.to[strlen(args.to)-1] = 0; /* strip ':' */
	            dvi->xdi_DOSName = args.to;
	          }
	          else
	            err = XADERR_NOMEMORY;
	        }
	        if(args.showtexts)
	        {
	          struct xadDiskInfo *xdi = ai->xai_DiskInfo;

	          while(xdi && xdi->xdi_EntryNumber < *args.entry)
	            xdi = xdi->xdi_Next;
	          if(xdi)
	          {
	            if(xdi->xdi_Flags & XADDIF_INFOTEXT)
	              Printf("»»INFOTEXT««\n%s\n", xdi->xdi_InfoText);
                    if(xdi->xdi_Flags & XADDIF_BANNER)
                      Printf("»»BANNER««\n%s\n", xdi->xdi_Banner);
	          }
	        }
	        if(!err && !(err = xadDiskUnArc(ai, dvi ? XAD_OUTDEVICE :
	        XAD_OUTFILENAME, dvi ? (ULONG) dvi : (ULONG) args.to,
	        XAD_ENTRYNUMBER, *args.entry, args.lowcyl ?
	        XAD_LOWCYLINDER : TAG_IGNORE, args.lowcyl ? *args.lowcyl :
	        0, args.highcyl ? XAD_HIGHCYLINDER : TAG_IGNORE,
	        args.highcyl ? *args.highcyl : 0, XAD_OVERWRITE,
	        args.overwrite, XAD_IGNOREGEOMETRY, args.ignoregeometry,
	        XAD_PROGRESSHOOK, &prhook, TAG_DONE)))
	          ret = 0;
	        if(dvi)
	          xadFreeObjectA(dvi, 0);
	      }
	      xadFreeInfo(ai);
	    } /* xadGetInfo */

	    xadFreeObjectA(ai, 0);
          } /* xadAllocObject */
        }
        else
          SetIoErr(ERROR_REQUIRED_ARG_MISSING);

        FreeArgs(rda);
      } /* ReadArgs */

      if(CTRL_C)
        SetIoErr(ERROR_BREAK);

      if(err)
	Printf("An error occured: %s\n", xadGetErrorText(err));
      else if(ret)
        PrintFault(IoErr(), 0);

      CloseLibrary((struct Library *) xadmasterbase);
    } /* OpenLibrary xadmaster */
    else
      Printf("Could not open xadmaster.library\n");
    CloseLibrary((struct Library *) dosbase);
  } /* OpenLibrary dos */
  return ret;
}

ASM(ULONG) SAVEDS progrhook(REG(a0, struct Hook *hook),
REG(a1, struct xadProgressInfo *pi))
{
  ULONG ret = 0;

  switch(pi->xpi_Mode)
  {
  case XADPMODE_ASK:
    {
      UBYTE r;
      if(pi->xpi_Status & XADPIF_OVERWRITE)
      {
        Printf("File already exists, overwrite? (Y|S|\033[1mN\033[0m): ");
        Flush(Output());
        SetMode(Input(), TRUE);
        r = FGetC(Input());
        if(r == 'Y' || r == 'y')
          ret |= XADPIF_OVERWRITE;
        else if(r == 'S' || r == 's')
          ret |= XADPIF_SKIP;
        SetMode(Input(), FALSE);
      }
      if(pi->xpi_Status & XADPIF_IGNOREGEOMETRY)
      {
        Printf("Drive geometry not correct, ignore? (Y|S|\033[1mN\033[0m): ");
        Flush(Output());
        SetMode(Input(), TRUE);
        r = FGetC(Input());
        if(r == 'Y' || r == 'y')
          ret |= XADPIF_IGNOREGEOMETRY;
        else if(r == 'S' || r == 's')
          ret |= XADPIF_SKIP;
        SetMode(Input(), FALSE);
      }
    }
    break;
  case XADPMODE_PROGRESS:
    {
      ULONG numcyl, fullsize, curcyl, i;

      i = pi->xpi_DiskInfo->xdi_CylSectors *
          pi->xpi_DiskInfo->xdi_SectorSize;
      numcyl = pi->xpi_HighCyl+1-pi->xpi_LowCyl;
      fullsize = numcyl * i;
      curcyl = pi->xpi_CurrentSize/i;

      Printf("\r\033[KWrote %ld of %ld bytes (%ld/%ld cylinders)",
      pi->xpi_CurrentSize, fullsize, curcyl, numcyl);
      Flush(Output());
    }
    break;
  case XADPMODE_END: Printf("\r\033[KWrote %ld bytes (%ld cylinders)\n",
    pi->xpi_CurrentSize, pi->xpi_HighCyl+1-pi->xpi_LowCyl);
    break;
  case XADPMODE_ERROR: Printf("\r\033[K");
    break;
  }

  if(!CTRL_C) /* clear ok flag */
    ret |= XADPIF_OK;

  return ret;
}
