/**************************************************************************/
/*                                                                        */
/*  Multitool II   -   DOS-Hilfsprogramm                Version 1.4r001   */
/*                                                                        */
/*  ©1992 Boris Jakubaschk                                                */
/*                                                                        */
/*  Modul 2 - Verzeichnisoperationen (Kopieren, Umtaufen,...)             */
/*                                                                        */
/**************************************************************************/

#include "MToolDefs.h"

#define GD_Length                              0
#define GD_DateStamp                           1
#define GD_Contents                            2
#define GD_Update                              3
#define GD_VerCheck                            4
#define GD_ChangeName                          5
#define GD_Start                               6
#define GD_Copy                                7
#define GD_Continue                            8
#define GD_Cancel                              9
#define GD_Name                                10

#define GDX_Length                             0
#define GDX_DateStamp                          1
#define GDX_Contents                           2
#define GDX_Update                             3
#define GDX_VerCheck                           4
#define GDX_ChangeName                         5
#define GDX_Start                              6
#define GDX_Copy                               7
#define GDX_Continue                           8
#define GDX_Cancel                             9
#define GDX_Name                               10

struct Window        *CopyWnd = NULL;
struct Gadget        *CopyGList = NULL;
struct Gadget        *CopyGadgets[11];
UWORD                 CopyLeft;
UWORD                 CopyTop;
UWORD                 CopyWidth;
UWORD                 CopyHeight;
UWORD                 CopyXSpc;
UWORD                 CopyYSpc;
char                  CopyTurbo;
char Length;
char DStamp;
char Contnt;
char VCheck;
char ChName;
char TempFile[] = "T:MT.temp";
USHORT Update;

UBYTE *Update0Labels[4];

/* ParentName   : Elternverzeichnis suchen. Übergabestring Dir wird von hinten
                  nach "/" und ":" durchsucht und bei Erfolg entsprechend ge-
                  kürzt.
    Dir           String. Achtung: wird verändert! */

ParentName( char *Dir )
    {
    int pos;
    
    pos = strlen( Dir )-1;
    while ( pos>0 & Dir[pos]!='/' & Dir[pos]!=':' ) pos--;
    if ( Dir[pos]=='/' ) Dir[pos]='\0';
    if ( Dir[pos]==':' ) Dir[pos+1]='\0';
    }


/* DirAction    : Kopiert, schiebt oder löscht die selektierten Dateien
                  und Verzeichnisse
    Act           0=linkes, 1=rechtes Dateienfenster
    What          0=kopieren, 1=schieben, 2=löschen */
/*  Status        0=nichts getan, 1=etwas getan, 2=Fehler */

DirAction( char Act, char What, ULONG Info )
    {
    ULONG a;
    int i;
    struct ExAllData *EAD;
    struct FileHandle *FH, *FH2;
    char Status = 0;
    char Command[256];
    char Buffer[130];
    LONG SysResponse;

    if ( TestSelect( Act ) )
        {
        if ( (VL_Archiv==~0)||((VL_Archiv==1-Act)&&(What==2)) )
            {
            if (What!=3) Status = OpenCopyWindow(What);
            }
        else WaitPointer( Wnd );
        if ( VL_Valid[Act] && ( VL_Valid[1-Act] | What>=2 ) && ( Status==0 ) )
            {
            if (VL_Archiv==Act)
                {
                if (PutMT_Temp( Act ))
                    {
                    switch (What)
                        {
                        case 0:
                        case 1: if (FH=(struct FileHandle *)OpenConsole())
                                    {
                                    strcpy( Buffer, VL_Name[1-Act] );
                                    AddPart( Buffer, "", 130 );
                                    sprintf( Command, Ana_Command[7], VL_Name[Act], Buffer );
                                    SysResponse = SystemTags( Command, SYS_Input, FH, SYS_Output, NULL, TAG_DONE);
                                    if (SysResponse!=0)
                                        ErrorMsg( LS[MSG_6_T_LHAFail] );
                                    CloseConsole(FH);
                                    if (What==1)
                                        {
                                        DirAction( Act, 2, 0 );
                                        What = 0;
                                        }
                                    else
                                        {
                                        ClrSelect( Act );
                                        ShowDir( Act, VL_OldFI[Act], 1 );
                                        };
                                    Status=1;
                                    };
                                break;
                        case 2: if (FH=(struct FileHandle *)OpenConsole())
                                    {
                                    sprintf( Command, Ana_Command[9], VL_Name[Act] ); 
                                    SysResponse = SystemTags( Command, SYS_Input, FH, SYS_Output, NULL, TAG_DONE);
                                    if (SysResponse!=0)
                                        ErrorMsg( LS[MSG_6_T_LHAFail] );
                                    CloseConsole(FH);
                                    Status=0;
                                    FileAktion( VL_Name[Act], 10 );
                                    GetArcList( Act, VL_Name[Act] );
                                    };
                                break;
                        case 3: VL_BytSel = 0;
                                VL_BlkSel = 0;
                                EAD = VL_Data[Act];
                                for (i=0; i<VL_NumEntry[Act]; i++)
                                    {
                                    if ( VL_Select[Act][i] )
                                        {
                                        VL_BytSel += EAD->ed_Size;
                                        VL_BlkSel += ((EAD->ed_Size-1)/Info)+2;
                                        };
                                    EAD = EAD->ed_Next;
                                    };
                                break;
                        };
                    RemMT_Temp();
                    };
                }
            else if (VL_Archiv==1-Act && What<2 )
                {
                if (PutMT_Temp( Act ))
                    {
                    if (FH=(struct FileHandle *)OpenConsole())
                        {
                        sprintf( Command, Ana_Command[8], VL_Name[1-Act] ); 
                        SysResponse = SystemTags( Command, SYS_Output, FH, TAG_DONE);
                        if (SysResponse!=0)
                            ErrorMsg( LS[MSG_6_T_LHAFail] );
                        CloseConsole(FH);
                        Status=0;
                        FileAktion( VL_Name[1-Act], 10 );
                        GetArcList( 1-Act, VL_Name[1-Act] );
                        if (What==1)
                            {
                            DirAction( Act, 2, 0 );
                            }
                        else
                            {
                            ClrSelect( Act );
                            ShowDir( Act, VL_OldFI[Act], 1 );
                            };
                        };
                    RemMT_Temp();
                    };
                }
            else
                {
                EAD = VL_Data[Act];

                if ( What==1 && IdentRoot() )
                    {
                    for (i=0; i<VL_NumEntry[Act] && Status<2; i++)
                        {
                        if ( VL_Select[Act][i] )
                            {
                            strcpy( Command, VL_Name[Act] );
                            AddPart( Command, EAD->ed_Name, 130 );
                            strcpy( Buffer, VL_Name[1-Act] );
                            AddPart( Buffer, EAD->ed_Name, 130 );
                            if (Rename(Command, Buffer))
                                {
                                VL_Select[Act][i]=0;
                                Status = 1;
                                if ( i>=VL_OldFI[Act] & i<VL_OldFI[Act]+LY_LNumLines )
                                    {
                                    ShowDirLine( Act, VL_OldFI[Act], i-VL_OldFI[Act] );
                                    };
                                }
                            else
                                {
                                Status = 2;
                                ErrorReq();
                                };
                            };
                        EAD = EAD->ed_Next;
                        };
                    }
                else
                    {
                    VL_BytSel = 0;
                    VL_BlkSel = 0;
                    for (i=0; i<VL_NumEntry[Act] && Status<2; i++)
                        {
                        if ( VL_Select[Act][i] && EAD->ed_Type<0 )
                            {
                            switch (What)
                                {
                                case 0 : Copy( VL_Name[Act], VL_Name[1-Act], EAD->ed_Name, &Status );
                                         break;
                                case 1 : MoveFile( VL_Name[Act], VL_Name[1-Act], EAD->ed_Name, &Status );
                                         break;
                                case 2 : Delete( VL_Name[Act], EAD->ed_Name, &Status );
                                         break;
                                case 3 : VL_BytSel += EAD->ed_Size;
                                         VL_BlkSel += ((EAD->ed_Size-1)/Info)+2;
                                         break;
                                };
                            }
                        else if ( VL_Select[Act][i] )
                            {
                            a = VL_BlkSel;
                            RekurOp( VL_Name[Act], VL_Name[1-Act], EAD->ed_Name, What, &Status );
                            if ((What==1 | What==2) & Status!=2)
                                Delete( VL_Name[Act], EAD->ed_Name, &Status );
                            if (What==3)
                                {
                                VL_BlkSel++;
                                EAD->ed_Size = (VL_BlkSel - a)*Info;
                                if ( i>=VL_OldFI[Act] & i<VL_OldFI[Act]+LY_LNumLines )
                                    {
                                    ShowDirLine( Act, VL_OldFI[Act], i-VL_OldFI[Act] );
                                    };
                                };
                            };
                        if ( Status!=2 & What!=3 )
                            {
                            VL_Select[Act][i]=0;
                            if ( i>=VL_OldFI[Act] & i<VL_OldFI[Act]+LY_LNumLines )
                                {
                                ShowDirLine( Act, VL_OldFI[Act], i-VL_OldFI[Act] );
                                };
                            };
                        EAD = EAD->ed_Next;
                        };
                    };
                };
            if (What!=0 & Status!=0) GetDir( Act, VL_Name[Act] );
            if (What!=2 & Status!=0) GetDir( 1-Act, VL_Name[1-Act] );
            };
        if ( (VL_Archiv==~0)||((VL_Archiv==1-Act)&&(What==2)) )
            {
            if (What!=3) CloseCopyWindow();
            }
        else StdPointer( Wnd );
        };
    }


long IdentRoot()
    {
    struct FileLock *FL1, *FL2;
    struct InfoData *IData1, *IData2;
    long a = 0;

    if ( FL1 = (struct FileLock *)Lock( VL_Name[0],ACCESS_READ ) )
        {
        if ( FL2 = (struct FileLock *)Lock( VL_Name[1],ACCESS_READ ) )
            {
            if (IData1 = (struct InfoData *)AllocMem( sizeof(struct InfoData), MEMF_ANY ))
                {
                if (IData2 = (struct InfoData *)AllocMem( sizeof(struct InfoData), MEMF_ANY ))
                    {
                    if ( Info((BPTR)FL1,IData1) && Info((BPTR)FL2,IData2) )
                        a = ( IData1->id_VolumeNode == IData2->id_VolumeNode );
                    FreeMem( IData1, sizeof(struct InfoData) );
                    };
                FreeMem( IData2, sizeof(struct InfoData) );
                };
            UnLock( (BPTR)FL2 );
            };
        UnLock( (BPTR)FL1 );
        };
    return( a );
    }
    

RekurOp( char *QV, char *ZV, char *Name, char What, char *Stat )
    {
    struct FileInfoBlock *FIB;
    struct FileLock *QFL, *ZFL;
    char DeleteIt = 0;
    int Status;
    char *Quelle, *Ziel, *ToDelete;

    if (FIB = AllocMem(sizeof(struct FileInfoBlock), MEMF_ANY))
        {
        if (Quelle = AllocMem(300, MEMF_ANY))
            {
            Ziel = Quelle+130;
            ToDelete = Quelle+260;
            strcpy( Quelle, QV );
            AddPart( Quelle, Name, 130 );
            if (QFL = (struct FileLock *)Lock( Quelle, ACCESS_READ ))
                {
                Status = Examine( (BPTR)QFL, FIB );
                if ( What<2 )
                    {
                    strcpy( Ziel, ZV );
                    AddPart( Ziel, Name, 130 );
                    if ( ZFL=(struct FileLock *)CreateDir( Ziel ) )
                        {
                        UnLock( (BPTR)ZFL );
                        }
                    };
                while ( Status & *Stat!=2 )
                    {
                    Status = ExNext( (BPTR)QFL, FIB );
                    if ( DeleteIt )
                        {
                        Delete( Quelle, ToDelete, Stat );
                        DeleteIt = 0;
                        };
                    if ( Status )
                        {
                        if ( FIB->fib_DirEntryType>0 )
                            {
                            RekurOp( Quelle, Ziel, FIB->fib_FileName, What, Stat );
                            if ( What==1 | What==2 )
                                {
                                strcpy( ToDelete, FIB->fib_FileName );
                                DeleteIt = 1;
                                };
                            if (What==3)
                                VL_BlkSel++;
                            }
                        else
                            {
                            switch (What)
                                {
                                case 0 : Copy( Quelle, Ziel, FIB->fib_FileName, Stat );
                                         break;
                                case 1 : Copy( Quelle, Ziel, FIB->fib_FileName, Stat );
                                         if (*Stat==1)
                                             {
                                             strcpy( ToDelete, FIB->fib_FileName );
                                             DeleteIt = 1;
                                             };
                                         break;
                                case 2 : strcpy( ToDelete, FIB->fib_FileName );
                                         DeleteIt = 1;
                                         break;
                                case 3:  VL_BytSel += FIB->fib_Size;
                                         VL_BlkSel += FIB->fib_NumBlocks+1;
                                         break;
                                };
                            };
                        };
                    };
                UnLock( (BPTR)QFL );
                }
            else ErrorReq();

            FreeMem( Quelle, 300 );
            };
        FreeMem( FIB, sizeof(struct FileInfoBlock) );
        };
    }


Copy( char *QV, char *ZV, char *Name, char *Stat )
    {
    char Quelle[130];
    char Ziel[130];
    char Buffer[30];
    char *CopyBlock;
    struct FileHandle *FHR, *FHW;
    struct FileLock *FL;
    struct InfoData *IData;
    LONG FileLen, MaxLen, CopyLen, BytesRead, BytesWritten, DestFree;

    AskCopyWindow( QV, ZV, Name, 1, Stat );

    if ((FL=(struct FileLock *)Lock(ZV,ACCESS_READ))!=0)
        {
        if (IData = (struct InfoData *)AllocMem(sizeof(struct InfoData), 0))
            {
            if (Info((BPTR)FL,IData))
                DestFree=(IData->id_NumBlocks - IData->id_NumBlocksUsed - 1) * IData->id_BytesPerBlock;
            FreeMem( IData, sizeof(struct InfoData) );
            };
        UnLock( (BPTR)FL );
        };

    strcpy(Quelle, QV);
    AddPart(Quelle, Name, 130);
    strcpy(Ziel, ZV);
    AddPart(Ziel, Name, 130);
    if (FHR = (struct FileHandle *)Open( Quelle, MODE_OLDFILE ))
        {
        Seek( (BPTR)FHR, 0, OFFSET_END );
        FileLen = Seek( (BPTR)FHR, 0, OFFSET_BEGINNING );
        if (*Stat==3)
            {
            *Stat=1;
            strcpy(Buffer, Name);
            if (StringRequest(LS[MSG_2_T_ExRename1],LS[MSG_2_T_ExRename2],Buffer))
                {
                strcpy(Ziel, ZV);
                AddPart(Ziel, Buffer, 130);
                };
            };
        if (*Stat==1)
            {
            if (FileLen<DestFree | DestFree<0)
                {
                if (FHW = (struct FileHandle *)Open( Ziel, MODE_NEWFILE ))
                    {
                    if (FileLen!=0)
                        {
                        do
                            {
                            MaxLen = (AvailMem(MEMF_LARGEST)*3)/4;
                            CopyLen = (MaxLen<FileLen) ? MaxLen : FileLen;
                            CopyBlock = AllocMem( CopyLen, MEMF_ANY );
                            }
                        while (CopyBlock==0);
                        do
                            {
                            BytesRead = Read( (BPTR)FHR, CopyBlock, (FileLen<CopyLen) ? FileLen : CopyLen );
                            BytesWritten = Write( (BPTR)FHW, CopyBlock, BytesRead );
                            FileLen = FileLen-CopyLen ;
                            }
                        while ( FileLen>0 & BytesRead!=0 );
                        if (BytesRead!=BytesWritten)
                            {
                            *Stat=2;
                            ErrorReq();
                            };
                        FreeMem( CopyBlock, CopyLen );
                        };
                    Close( (BPTR)FHW );
                    }
                else ErrorReq();
                }
            else ErrorMsg( LS[MSG_2_T_DestFull] );
            }
        Close( (BPTR)FHR );
        }
    else ErrorReq();
    }

    
MoveFile( char *QV, char *ZV, char *Name, char *Stat )
    {
    Copy( QV, ZV, Name, Stat );
    if (*Stat==1) Delete( QV, Name, Stat );
    }


Delete( char *QV, char *Name, char *Stat )
    {
    char Quelle[130];

    AskCopyWindow( QV, "", Name, 2, Stat );

    if ((*Stat==1)||(*Stat==3))
        {
        *Stat=1;
        strcpy(Quelle, QV);
        if ( Name[0]!='\0' ) AddPart(Quelle, Name, 130);
        if (NOT DeleteFile( Quelle ))
            {
            *Stat=2;    
            ErrorReq();
            };
        };
    }


MakeADir( Act )
    {
    char Buffer[30];
    char DirName[130];
    struct FileLock *FL;

    Buffer[0]='\0';

    if (StringRequest(LS[MSG_2_T_MakeDir1], LS[MSG_2_T_MakeDir2], Buffer ))
        {
        strcpy(DirName, VL_Name[Act]);
        AddPart(DirName, Buffer, 130);
        if (FL=(struct FileLock *)CreateDir(DirName))
            {
            UnLock((BPTR)FL);
            GetDir(Act, VL_Name[Act]);
            }
        else ErrorReq();
        };
    }


ReNameSel( Act )
    {
    int i;
    char Buffer[30];
    char NameOld[130];
    char NameNew[130];
    struct FileLock *FL;
    struct ExAllData *EAD;
    char Changed = 0;    

    EAD = VL_Data[Act];
    
    if (TestSelect( Act ))
        {
        for (i=0; i<VL_NumEntry[Act]; i++)
            {
            if (VL_Select[Act][i])
                {
                strcpy(Buffer, EAD->ed_Name);
                if (StringRequest(LS[MSG_2_T_ReName], Buffer, Buffer ))
                    {
                    if (strcmp(Buffer, EAD->ed_Name))
                        {
                        strcpy(NameOld, VL_Name[Act]);
                        AddPart(NameOld, EAD->ed_Name, 130);
                        strcpy(NameNew, VL_Name[Act]);
                        AddPart(NameNew, Buffer, 130);
                        if (Rename(NameOld, NameNew))
                            {
                            Changed=1;
                            VL_Select[Act][i]=0;
                            if ( i>=VL_OldFI[Act] & i<VL_OldFI[Act]+LY_LNumLines )
                                {
                                ShowDirLine( Act, VL_OldFI[Act], i-VL_OldFI[Act] );
                                };
                            }
                        else ErrorReq();
                        };
                    };
                };
            EAD = EAD->ed_Next;
            };
        if (Changed) GetDir(Act, VL_Name[Act]);
        };
    }


/* ChgSelect   : Ändert den Auswahlstatus eines Objekts */

ChgSelect( char *Item )
    {
    *Item = ~(*Item);
    }


/* ClrSelect   : Wählt alle Objekte einer Liste ab */

ClrSelect( char Act )
    {
    memset(VL_Select[Act],0,VL_NumEntry[Act]);
    ShowDir( Act, VL_OldFI[Act], 1);
    }


/* AllSelect   : Wählt alle Objekte einer Liste an */

AllSelect( char Act )
    {
    memset(VL_Select[Act],255,VL_NumEntry[Act]);
    ShowDir( Act, VL_OldFI[Act], 1);
    }


/* MaskSelect  : Fordert vom Benutzer eine Maske an, anhand derer die
                 Objekte der Dateienliste selektiert werden - oder nicht. */

MaskSelect( char Act )
    {
    int i;
    char ProcMaske[100];
    char Buffer[30];
    struct ExAllData *EAD;

    strcpy( Buffer, Maske );
    if (StringRequest(LS[MSG_2_T_PatSel1], LS[MSG_2_T_PatSel2], Buffer ))
        {
        strcpy( Maske, Buffer );
        if (ParsePattern( Maske, ProcMaske, 100 ))
            {
            EAD = VL_Data[Act];
            for (i=0; i<VL_NumEntry[Act]; i++)
                {
                if (MatchPattern(ProcMaske, EAD->ed_Name))
                    VL_Select[Act][i]=255;
                EAD = EAD->ed_Next;
                };
            ShowDir( Act, VL_OldFI[Act], 1);
            };
        };
    }


int TestSelect( char Act )
    {
    int i;

    for (i=0; (i<VL_NumEntry[Act]) && (VL_Select[Act][i]==0); i++);
    if (i==VL_NumEntry[Act])
        {
        ErrorMsg( LS[MSG_2_T_NoSourceFile] );
        return( 0 );
        }
    else
        {
        return( 1 );
        };
    }


void CopyRender( void )
{
    UWORD        offx, offy;
    struct IntuiText  CopyIText[] = {
        1, 0, JAM1,17, 13, &GadgetFont, (UBYTE *)LS[MSG_2_T_CheckThese], &CopyIText[1],
        1, 0, JAM1,CopyWidth - 50*CopyXSpc - 10, 24+4*CopyYSpc, &GadgetFont, (UBYTE *)LS[MSG_2_T_SourceFile], &CopyIText[2],
        1, 0, JAM1,CopyWidth - 25*CopyXSpc - 4, 24+4*CopyYSpc, &GadgetFont, (UBYTE *)LS[MSG_2_T_DestFile], &CopyIText[3],
        1, 0, JAM1,17, 28+5*CopyYSpc, &GadgetFont, (UBYTE *)LS[MSG_2_T_Length], &CopyIText[4],
        1, 0, JAM1,17, 28+6*CopyYSpc, &GadgetFont, (UBYTE *)LS[MSG_2_T_Date], &CopyIText[5],
        1, 0, JAM1,17, 28+7*CopyYSpc, &GadgetFont, (UBYTE *)LS[MSG_2_T_Contents], &CopyIText[6],
        1, 0, JAM1,17, 28+8*CopyYSpc, &GadgetFont, (UBYTE *)LS[MSG_2_T_Version], &CopyIText[7],
        1, 0, JAM1,17, 32+9*CopyYSpc, &GadgetFont, (UBYTE *)LS[MSG_2_T_Name], NULL };


    offx = CopyWnd->BorderLeft;
    offy = CopyWnd->BorderTop;

    PrintIText( CopyWnd->RPort, CopyIText, offx, offy );

    DrawBevelBox( CopyWnd->RPort, offx + CopyWidth - 50*CopyXSpc - 20, offy + 22+5*CopyYSpc, 25*CopyXSpc, 4+4*CopyYSpc, GT_VisualInfo, VisualInfo, GTBB_Recessed, TRUE, TAG_DONE );
    DrawBevelBox( CopyWnd->RPort, offx + CopyWidth - 25*CopyXSpc - 14, offy + 22+5*CopyYSpc, 25*CopyXSpc, 4+4*CopyYSpc, GT_VisualInfo, VisualInfo, GTBB_Recessed, TRUE, TAG_DONE );
    DrawBevelBox( CopyWnd->RPort, offx + 8, offy + 4, CopyWidth-22, 16+4*CopyYSpc, GT_VisualInfo, VisualInfo, GTBB_Recessed, TRUE, TAG_DONE );
}

int OpenCopyWindow( char What )
{
    struct NewGadget     ng;
    struct Gadget       *g;
    UWORD               offx, offy;
    char                Stat = 0;
    struct TextFont     *TestFont;
    UBYTE               *CopyWdt = (UBYTE *)LS[MSG_2_T_CopDel];

    offx = Scr->WBorLeft;
    offy = Scr->WBorTop + Scr->RastPort.TxHeight + 1;
    CopyYSpc = LY_GFontH + 5;
    CopyXSpc = Wnd->RPort->TxWidth;

    Update0Labels[0]=(UBYTE *)LS[MSG_2_T_ConfEvryFile];
    Update0Labels[1]=(UBYTE *)LS[MSG_2_T_ConfExisFile];
    Update0Labels[2]=(UBYTE *)LS[MSG_2_T_ConfAllFile];
    Update0Labels[3]=NULL;

    if (What<=1)
       {
       Update = (CM&0x0C00)>>10;
       }
    else Update = (CM&0x3000)>>12;

    if ( TestFont=(struct TextFont *)OpenDiskFont( &GadgetFont ) )
        {
        CopyXSpc = TestFont->tf_XSize;
        CloseFont( TestFont );
        };

    CopyWidth = offx + 38 + 60*CopyXSpc;
    CopyHeight = offy + 43 + 11*CopyYSpc;
    CopyLeft = (Scr->Width-CopyWidth)/2;
    CopyTop = (Scr->Height-CopyHeight)/2;

    if ( ! ( g = CreateContext( &CopyGList )))
        return( 1L );

    ng.ng_LeftEdge        =    offx + 17;
    ng.ng_TopEdge         =    offy + 12 + CopyYSpc;
    ng.ng_Width           =    26;
    ng.ng_Height          =    CopyYSpc-2;
    ng.ng_GadgetText      =    (UBYTE *)LS[MSG_2_G_Length];
    ng.ng_TextAttr        =    &GadgetFont;
    ng.ng_GadgetID        =    GD_Length;
    ng.ng_Flags           =    PLACETEXT_RIGHT;
    ng.ng_VisualInfo      =    VisualInfo;

    g = CreateGadget( CHECKBOX_KIND, g, &ng, GT_Underscore, '_', TAG_DONE );

    CopyGadgets[ 0 ] = g;

    ng.ng_TopEdge         =    offy + 13 + 2*CopyYSpc;
    ng.ng_GadgetText      =    (UBYTE *)LS[MSG_2_G_Date];
    ng.ng_GadgetID        =    GD_DateStamp;

    g = CreateGadget( CHECKBOX_KIND, g, &ng, GT_Underscore, '_', TAG_DONE );

    CopyGadgets[ 1 ] = g;

    ng.ng_TopEdge         =    offy + 14 + 3*CopyYSpc;
    ng.ng_GadgetText      =    (UBYTE *)LS[MSG_2_G_Contents];
    ng.ng_GadgetID        =    GD_Contents;

    g = CreateGadget( CHECKBOX_KIND, g, &ng, GT_Underscore, '_', TAG_DONE );

    CopyGadgets[ 2 ] = g;

    ng.ng_LeftEdge        =    offx + 46 + 22*CopyXSpc;
    ng.ng_TopEdge         =    offy + 8;
    ng.ng_Width           =    CopyWidth-ng.ng_LeftEdge-20;
    ng.ng_Height          =    CopyYSpc+1;
    ng.ng_GadgetText      =    NULL;
    ng.ng_GadgetID        =    GD_Update;
    ng.ng_Flags           =    0;

    g = CreateGadget( CYCLE_KIND, g, &ng, GTCY_Labels, &Update0Labels[0], GTCY_Active, Update, TAG_DONE );

    CopyGadgets[ 3 ] = g;

    ng.ng_TopEdge         =    offy + 12 + CopyYSpc;
    ng.ng_GadgetText      =    (UBYTE *)LS[MSG_2_G_Version];
    ng.ng_GadgetID        =    GD_VerCheck;
    ng.ng_Flags           =    PLACETEXT_RIGHT;

    g = CreateGadget( CHECKBOX_KIND, g, &ng, GT_Underscore, '_', TAG_DONE );

    CopyGadgets[ 4 ] = g;

    ng.ng_TopEdge         =    offy + 13 + CopyYSpc*2;
    ng.ng_GadgetText      =    (UBYTE *)LS[MSG_2_G_ChngName];
    ng.ng_GadgetID        =    GD_ChangeName;

    g = CreateGadget( CHECKBOX_KIND, g, &ng, GT_Underscore, '_', TAG_DONE );

    CopyGadgets[ 5 ] = g;

    ng.ng_TopEdge         =    offy + 14 + CopyYSpc*3;
    ng.ng_Width           =    CopyWidth-ng.ng_LeftEdge-20;
    ng.ng_Height          =    CopyYSpc+1;
    ng.ng_GadgetText      =    (UBYTE *)LS[MSG_2_G_Start];
    ng.ng_GadgetID        =    GD_Start;
    ng.ng_Flags           =    PLACETEXT_IN;

    g = CreateGadget( BUTTON_KIND, g, &ng, GT_Underscore, '_', TAG_DONE );

    CopyGadgets[ 6 ] = g;

    ng.ng_LeftEdge        =    offx + 8;
    ng.ng_TopEdge         =    offy + 36 + CopyYSpc*10;
    ng.ng_Width           =    3+20*CopyXSpc;
    ng.ng_GadgetText      =    (UBYTE *)((What!=2)? LS[MSG_2_G_Copy] : LS[MSG_2_G_Delete]);
    ng.ng_GadgetID        =    GD_Copy;

    g = CreateGadget( BUTTON_KIND, g, &ng, GT_Underscore, '_', TAG_DONE );

    CopyGadgets[ 7 ] = g;

    ng.ng_LeftEdge        =    offx + 15 + 20*CopyXSpc;
    ng.ng_GadgetText      =    (UBYTE *)LS[MSG_2_G_Continue];
    ng.ng_GadgetID        =    GD_Continue;

    g = CreateGadget( BUTTON_KIND, g, &ng, GT_Underscore, '_', TAG_DONE );

    CopyGadgets[ 8 ] = g;

    ng.ng_LeftEdge        =    offx + 22 + 40*CopyXSpc;
    ng.ng_GadgetText      =    (UBYTE *)LS[MSG_2_G_Cancel];
    ng.ng_GadgetID        =    GD_Cancel;

    g = CreateGadget( BUTTON_KIND, g, &ng, GT_Underscore, '_', TAG_DONE );

    CopyGadgets[ 9 ] = g;

    ng.ng_LeftEdge        =    offx + CopyWidth - 50*CopyXSpc - 20;
    ng.ng_TopEdge         =    offy + 29 + 9*CopyYSpc;
    ng.ng_Width           =    CopyWidth-ng.ng_LeftEdge-10;
    ng.ng_GadgetText      =    NULL;
    ng.ng_GadgetID        =    GD_Name;
    ng.ng_Flags           =    0;

    g = CreateGadget( TEXT_KIND, g, &ng, GTTX_Border, TRUE, TAG_DONE );

    CopyGadgets[ 10 ] = g;

    if ( ! g )
        return( 2L );

    if ( ! ( CopyWnd = OpenWindowTags( NULL,
                    WA_Left,          CopyLeft,
                    WA_Top,           CopyTop,
                    WA_Width,         CopyWidth,
                    WA_Height,        CopyHeight,
                    WA_IDCMP,         CHECKBOXIDCMP|CYCLEIDCMP|BUTTONIDCMP|TEXTIDCMP|IDCMP_CLOSEWINDOW|IDCMP_REFRESHWINDOW|IDCMP_INTUITICKS|IDCMP_VANILLAKEY,
                    WA_Flags,         WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET|WFLG_SMART_REFRESH|WFLG_ACTIVATE,
                    WA_Gadgets,       CopyGList,
                    WA_Title,         CopyWdt,
                    WA_PubScreen,     Scr,
                    TAG_DONE )))
        return( 4L );

    GT_RefreshWindow( CopyWnd, NULL );

    CopyRender();

    Length = ((CM&1)==0)?0:255;
    DStamp = ((CM&2)==0)?0:255;
    Contnt = ((CM&4)==0)?0:255;
    VCheck = ((CM&8)==0)?0:255;
    ChName = ((CM&32)==0)?0:255;
    CopyTurbo = 0;
    if (Length) GT_SetGadgetAttrs( CopyGadgets[GD_Length], CopyWnd, 0, GTCB_Checked, TRUE, TAG_DONE );
    if (DStamp) GT_SetGadgetAttrs( CopyGadgets[GD_DateStamp], CopyWnd, 0, GTCB_Checked, TRUE, TAG_DONE );
    if (Contnt) GT_SetGadgetAttrs( CopyGadgets[GD_Contents], CopyWnd, 0, GTCB_Checked, TRUE, TAG_DONE );
    if (VCheck) GT_SetGadgetAttrs( CopyGadgets[GD_VerCheck], CopyWnd, 0, GTCB_Checked, TRUE, TAG_DONE );
    if (ChName) GT_SetGadgetAttrs( CopyGadgets[GD_ChangeName], CopyWnd, 0, GTCB_Checked, TRUE, TAG_DONE );

    if (What==2)
        {
        GT_SetGadgetAttrs( CopyGadgets[GD_Contents], CopyWnd, 0, GA_Disabled, TRUE, TAG_DONE );
        GT_SetGadgetAttrs( CopyGadgets[GD_VerCheck], CopyWnd, 0, GA_Disabled, TRUE, TAG_DONE );
        GT_SetGadgetAttrs( CopyGadgets[GD_ChangeName], CopyWnd, 0, GA_Disabled, TRUE, TAG_DONE );
        };

    if (((CM & 16)==0) || (What==2))
        AskCopyWindow( "", "", "", -What, &Stat );
    if ((Stat==1)|(Stat==3)) Stat=0;
    return( (int)Stat );
}

CloseCopyWindow( void )
{
    CM &= 0x3F10;
    CM = CM + ((Length!=0)?1:0) + ((DStamp!=0)?2:0) + ((Contnt!=0)?4:0) + ((VCheck!=0)?8:0) + ((ChName!=0)?32:0);

    if ( CopyWnd        ) {
        CloseWindow( CopyWnd );
        CopyWnd = NULL;
    }

    if ( CopyGList      ) {
        FreeGadgets( CopyGList );
        CopyGList = NULL;
    }
}

int AskCopyWindow( char *QV, char *ZV, char *Name, char What, char *Stat )
    {
    char Exit = 0;
    ULONG  GClass;
    USHORT GCode;
    struct Gadget *GList;
    struct IntuiMessage *msg;
    struct DateTime DT;
    struct FileHandle *RFH, *WFH, *FH;
    struct TextFont *Font;
    char   FileName[130];
    char   Buffer[130];
    BPTR   FL1, FL2;
    struct FileInfoBlock *FIB;
    UWORD  offx, offy, x1, x2, y1;
    ULONG  len, a, b;
    char  *CompareBuffer;
    char  *Key = LS[MSG_2_T_Keys];
    char   equal;

    GT_SetGadgetAttrs( CopyGadgets[GD_Name], CopyWnd, 0, GTTX_Text, Name, TAG_DONE );
    *Stat = 1;

    if (CopyTurbo==0)
        {
        offx = Scr->WBorLeft;
        offy = Scr->WBorTop + Scr->RastPort.TxHeight + 1;
        x1 = offx + CopyWidth - 50*CopyXSpc - 16;
        x2 = offx + CopyWidth - 25*CopyXSpc - 10;
        y1 = offy + 33;

        DT.dat_Format = FORMAT_DOS;
        DT.dat_Flags = 0;

        SetAPen( CopyWnd->RPort, 0 );
        RectFill( CopyWnd->RPort, x1, offy + 24+5*CopyYSpc, offx + CopyWidth - 25*CopyXSpc - 24, offy + 24+9*CopyYSpc);
        RectFill( CopyWnd->RPort, x2, offy + 24+5*CopyYSpc, offx + CopyWidth - 18, offy + 24+9*CopyYSpc);

        if (Font=(struct TextFont *)OpenDiskFont( &GadgetFont ))
           {
           SetFont( CopyWnd->RPort, Font );
           y1 = offy + 27 + Font->tf_Baseline;
           };

        *Stat = 3;
        if (What>0)
            {
            GT_SetGadgetAttrs( CopyGadgets[GD_Start], CopyWnd, 0, GA_Disabled, TRUE, TAG_DONE );
            SetAPen( CopyWnd->RPort, 1 );
            if( FIB=AllocMem( sizeof(struct FileInfoBlock), MEMF_ANY ) )
                {
                strcpy( FileName, QV );
                AddPart( FileName, Name, 130 );
                if( RFH=(struct FileHandle *)Open( FileName, MODE_OLDFILE ) )
                    {
                    ExamineFH( (BPTR)RFH, FIB );
                    len = FIB->fib_Size;
                    if (Length)
                        {
                        SPrintGroup( Buffer, len, 14 );
                        Move( CopyWnd->RPort, x1, y1+5*CopyYSpc );
                        Text( CopyWnd->RPort, Buffer, strlen(Buffer) );
                        };
                    if (DStamp)
                        {
                        DT.dat_StrDay = Buffer+100;
                        DT.dat_StrDate = Buffer;
                        DT.dat_StrTime = Buffer+20;
                        DT.dat_Stamp.ds_Days = FIB->fib_Date.ds_Days;
                        DT.dat_Stamp.ds_Minute = FIB->fib_Date.ds_Minute;
                        DT.dat_Stamp.ds_Tick = FIB->fib_Date.ds_Tick;
                        if ( DateToStr( &DT ) )
                            {
                            Move( CopyWnd->RPort, x1, y1 + 6*CopyYSpc );
                            Text( CopyWnd->RPort, Buffer, strlen(Buffer) );
                            Move( CopyWnd->RPort, x1+10*CopyXSpc, y1 + 6*CopyYSpc );
                            Text( CopyWnd->RPort, Buffer+20, strlen(Buffer+20) );
                            };
                        };
                    if (VCheck)
                        {
                        if (FL1 = Lock( QV, ACCESS_READ ))
                            {
                            FL2 = CurrentDir( FL1 );
                            sprintf( Buffer, "Version >%s %s FULL", TempFile, Name );
                            SystemTags( Buffer, TAG_DONE );
                            CurrentDir( FL2 );
                            if( FH=(struct Filehandle *)Open( TempFile, MODE_OLDFILE ) )
                                {
                                if (a = Read( (BPTR)FH, Buffer, 25 ))
                                    {
                                    Move( CopyWnd->RPort, x1, y1 + 8*CopyYSpc );
                                    Text( CopyWnd->RPort, Buffer, a-1 );
                                    };
                                Close( (BPTR)FH );
                                };
                            DeleteFile( TempFile );
                            };
                        };
                    if (What==1)
                        {
                        strcpy( FileName, ZV );
                        AddPart( FileName, Name, 130 );
                        if( WFH=(struct FileHandle *)Open( FileName, MODE_OLDFILE ) )
                            {
                            ExamineFH( (BPTR)WFH, FIB );
                            if (Length)
                                {
                                SPrintGroup( Buffer, FIB->fib_Size, 14 );
                                Move( CopyWnd->RPort, x2, y1 + 5*CopyYSpc );
                                Text( CopyWnd->RPort, Buffer, strlen(Buffer) );
                                };
                            if (DStamp)
                                {
                                DT.dat_StrDay = Buffer+100;
                                DT.dat_StrDate = Buffer;
                                DT.dat_StrTime = Buffer+20;
                                DT.dat_Stamp.ds_Days = FIB->fib_Date.ds_Days;
                                DT.dat_Stamp.ds_Minute = FIB->fib_Date.ds_Minute;
                                DT.dat_Stamp.ds_Tick = FIB->fib_Date.ds_Tick;
                                if ( DateToStr( &DT ) )
                                    {
                                    Move( CopyWnd->RPort, x2, y1 + 6*CopyYSpc );
                                    Text( CopyWnd->RPort, Buffer, strlen(Buffer) );
                                    Move( CopyWnd->RPort, x2+10*CopyXSpc, y1 + 6*CopyYSpc );
                                    Text( CopyWnd->RPort, Buffer+20, strlen(Buffer+20) );
                                    };
                                };
                            if ((Contnt) && (FIB->fib_Size == len))
                                {
                                if (CompareBuffer=AllocMem( 65536, MEMF_ANY ))
                                    {
                                    Move( CopyWnd->RPort, x1, y1 + 7*CopyYSpc );
                                    equal = 1;
                                    do
                                        {
                                        a = Read( (BPTR)RFH, CompareBuffer, 32768 );
                                        b = Read( (BPTR)WFH, CompareBuffer+32768, 32768 );
                                        equal = (memcmp( CompareBuffer, CompareBuffer+32768, a )==0);
                                        } while ( (a==b) && (a==32768) && (equal) );
                                    if (a>b)
                                        {
                                        Move( CopyWnd->RPort, x2, y1 + 7*CopyYSpc );
                                        Text( CopyWnd->RPort, LS[MSG_2_T_ReadError], strlen(LS[MSG_2_T_ReadError]) );
                                        }
                                    else if (a<b)
                                        {
                                        Text( CopyWnd->RPort, LS[MSG_2_T_ReadError], strlen(LS[MSG_2_T_ReadError]) );
                                        }
                                    else if (equal)
                                        {
                                        Text( CopyWnd->RPort, LS[MSG_2_T_FilesIdent], strlen(LS[MSG_2_T_FilesIdent]) );
                                        }
                                    else
                                        {
                                        Text( CopyWnd->RPort, LS[MSG_2_T_FilesDiff], strlen(LS[MSG_2_T_FilesDiff]) );
                                        };
                                    FreeMem( CompareBuffer, 65536 );
                                    }
                                }
                            else if (Contnt)
                                {
                                Move( CopyWnd->RPort, x1, y1 + 7*CopyYSpc );
                                Text( CopyWnd->RPort, LS[MSG_2_T_FiLenDiff], strlen(LS[MSG_2_T_FiLenDiff]) );
                                };
                            if (VCheck)
                                {
                                if (FL1 = Lock( ZV, ACCESS_READ ))
                                    {
                                    FL2 = CurrentDir( FL1 );
                                    sprintf( Buffer, "Version >%s %s FULL", TempFile, Name );
                                    SystemTags( Buffer, TAG_DONE );
                                    CurrentDir( FL2 );
                                    if( FH=(struct Filehandle *)Open( TempFile, MODE_OLDFILE ) )
                                        {
                                        if (a = Read( (BPTR)FH, Buffer, 25 ))
                                            {
                                            Move( CopyWnd->RPort, x2, y1 + 8*CopyYSpc );
                                            Text( CopyWnd->RPort, Buffer, a-1 );
                                            };
                                        Close( (BPTR)FH );
                                        };
                                    DeleteFile( TempFile );
                                    };
                                };
                            Close( (BPTR)WFH );
                            }
                        else
                            {
                            Move( CopyWnd->RPort, x2, y1 + 6*CopyYSpc + CopyYSpc/2);
                            Text( CopyWnd->RPort, LS[MSG_2_T_NoExist], strlen(LS[MSG_2_T_NoExist]) );
                            *Stat=1;
                            };
                        };
                    Close( (BPTR)RFH );
                    };
                FreeMem( FIB, sizeof(struct FileInfoBlock) );
                };
            };

        while (Exit==0)
		{
		Wait(1 << CopyWnd->UserPort->mp_SigBit);
		while ( msg = (struct IntuiMessage *) GT_GetIMsg(CopyWnd->UserPort))
		    {
		    GClass  = msg->Class;
		    GCode   = msg->Code;
		    if (GClass & GADGETUP)
                    GList   = (struct Gadget *) msg->IAddress;
		    GT_ReplyIMsg(msg);
		    switch (GClass)
			{
	  	    case CLOSEWINDOW :
                        Exit=1;
                        *Stat=2;
                        break;
                    case GADGETUP    :
                        switch (GList->GadgetID)
                            {
                            case GD_Cancel    : Exit=1;
                                                *Stat=2;
                                                break;
                            case GD_Length    : Length = ~Length;
                                                break;
                            case GD_DateStamp : DStamp = ~DStamp;
                                                break;
                            case GD_Contents  : Contnt = ~Contnt;
                                                break;
                            case GD_Update    : Update = GCode;
                                                if (((What==2)|(What==-2))&&(Update==1))
                                                    {
                                                    Update=2;
                                                    GT_SetGadgetAttrs( CopyGadgets[GD_Update], CopyWnd, 0, GTCY_Active, Update, TAG_DONE );
                                                    };
                                                if ((What==2)|(What==-2))
                                                    {
                                                    CM &= 0x0FFF;
                                                    CM += Update<<12;
                                                    }
                                                else
                                                    {
                                                    CM &= 0x33FF;
                                                    CM += Update<<10;
                                                    };
                                                break;
                            case GD_VerCheck  : VCheck = ~VCheck;
                                                break;
                            case GD_ChangeName: ChName = ~ChName;
                                                break;
                            case GD_Start     : Exit=1;
                                                break;
                            case GD_Copy      : Exit=1;
                                                break;
                            case GD_Continue  : Exit=1;
                                                *Stat=0;
                                                break;
                            };
                        break;
                    case VANILLAKEY  :
                        for (a=0; a<10 & Key[a]!=GCode; a++);
                        switch (a)
                            {
                            case 0 : Exit=1;
                                     *Stat=2;
                                     break;
                            case 1 : Length = ~Length;
                                     GT_SetGadgetAttrs( CopyGadgets[GD_Length], CopyWnd, 0, GTCB_Checked, (Length!=0) , TAG_DONE );
                                     break;
                            case 2 : DStamp = ~DStamp;
                                     GT_SetGadgetAttrs( CopyGadgets[GD_DateStamp], CopyWnd, 0, GTCB_Checked, (DStamp!=0) , TAG_DONE );
                                     break;
                            case 3 : Contnt = ~Contnt;
                                     GT_SetGadgetAttrs( CopyGadgets[GD_Contents], CopyWnd, 0, GTCB_Checked, (Contnt!=0) , TAG_DONE );
                                     break;
                            case 4 : VCheck = ~VCheck;
                                     GT_SetGadgetAttrs( CopyGadgets[GD_VerCheck], CopyWnd, 0, GTCB_Checked, (VCheck!=0) , TAG_DONE );
                                     break;
                            case 5 : ChName = ~ChName;
                                     GT_SetGadgetAttrs( CopyGadgets[GD_ChangeName], CopyWnd, 0, GTCB_Checked, (ChName!=0) , TAG_DONE );
                                     break;
                            case 6 :
                            case 7 :
                            case 8 : Exit=1;
                                     break;
                            case 9 : Exit=1;
                                     *Stat=0;
                                     break;
                            };
                        if(GCode==13)
                            {
                            CopyTurbo=1;
                            Exit=1;
                            SetAPen( CopyWnd->RPort, 0 );
                            RectFill( CopyWnd->RPort, x1, offy + 24+5*CopyYSpc, offx + CopyWidth - 25*CopyXSpc - 24, offy + 24+9*CopyYSpc);
                            RectFill( CopyWnd->RPort, x2, offy + 24+5*CopyYSpc, offx + CopyWidth - 18, offy + 24+9*CopyYSpc);
                            };
                        break;
			};
		    };
		if ((Update>=2) && (What>0)) Exit=1;
		if ((Update==1) && (WFH==0) && (What>0)) Exit=1;
		};
        if (*Stat==3) *Stat = (Update==2) ? 3 : 1;
        CloseFont( Font );
        };
    }
