/*

Directory Opus 4
Original GPL release version 4.12
Copyright 1993-2000 Jonathan Potter

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

All users of Directory Opus 4 (including versions distributed
under the GPL) are entitled to upgrade to the latest version of
Directory Opus version 5 at a reduced price. Please see
http://www.gpsoft.com.au for more information.

The release of Directory Opus 4 under the GPL in NO WAY affects
the existing commercial status of Directory Opus 5.

*/

#include "dopus.h"
#define ASIO_REGARGS
#include <clib/asyncio_protos.h>
//#include <inline/asyncio.h>

copyfile(src,dst,err,size,password,encryptstate)
char *src,*dst;
int *err,size;
char *password;
int encryptstate;
{
    char *buffer;
    struct FileInfoBlock __aligned cfinfo;
    int out,length,suc,readsize,size_read,size_write,size_total,ret=0,prog=0,buffer_size;
    int inhandle;
    int outhandle;
    struct AsyncFile *infile;
/*
    struct AsyncFile *outfile;
*/
    struct DateStamp ds,*dsp;
    ULONG owner_info;

    buffer=NULL;
    infile=NULL;
/*
    outfile=NULL;
*/
    inhandle=0;
    outhandle=0;

    if (password) {
        int a,encrypt=1;

        for (a=0;password[a];a++) encrypt*=password[a];
        Seed(encrypt);
    }

    if (config->dynamicflags&UPDATE_PROGRESSIND_COPY) prog=1;

    suc=lockandexamine(src,&cfinfo);

    if (size==0) {
        if (suc) {
            if (cfinfo.fib_Size==0) {
                if ((out=Open(dst,MODE_NEWFILE))) Close(out);
                else goto failed;
            }
            if (config->copyflags&COPY_DATE) setdate(dst,&(cfinfo.fib_Date));
            if (config->copyflags&COPY_PROT) SetProtection(dst,cfinfo.fib_Protection);
            if (config->copyflags&COPY_NOTE) SetComment(dst,cfinfo.fib_Comment);
//            if (system_version2) {
                owner_info=(cfinfo.fib_OwnerUID<<16)|cfinfo.fib_OwnerGID;
                if (owner_info) SetOwner(dst,owner_info);
//            }
        }
        filloutcopydatafile(dst);
        if (suc) return(1);
    }

    if (!suc) {
        *err=IoErr();
        return(0);
    }

    if (!(size=cfinfo.fib_Size)) {
        if (!(out=Open(dst,MODE_NEWFILE))) goto failed;
        Close(out);
        return(1);
    }

    if (size<=COPY_BUF_SIZE) {
        dotaskmsg(hotkeymsg_port,PROGRESS_UPDATE,100,100,NULL,1);
        prog=0;
    }
    else dotaskmsg(hotkeymsg_port,PROGRESS_UPDATE,0,100,NULL,1);

/*
    if (prog) {
        buffer_size=COPY_BUF_SIZE;
        buffer=AllocMem(COPY_BUF_SIZE,0);
        if (infile=OpenAsync(src,MODE_READ,ASYNC_READ_SIZE))
            outfile=OpenAsync(dst,MODE_WRITE,ASYNC_WRITE_SIZE);
        if (!outfile) goto failed;
    }
    else {
        if (size>65536) buffer_size=size/2;
        else buffer_size=size;
        if (buffer_size>122880) buffer_size=122880;

        while (buffer_size>0) {
            if (buffer=AllocMem(buffer_size,0)) break;
            buffer_size/=2;
        }
        if (inhandle=Open(src,MODE_OLDFILE))
            outhandle=Open(dst,MODE_NEWFILE);
        if (!outhandle) goto failed;
    }

    if (!buffer) goto failed;
*/

    if (prog) {
//        buffer_size=COPY_BUF_SIZE;
        infile=OpenAsync(src,MODE_READ,ASYNC_READ_SIZE);
    }
    /*else*/ {
        if (size>65536) buffer_size=size/2;
        else buffer_size=size;
        if (buffer_size>122880) buffer_size=122880;
    }

    while (buffer_size>0) {
        if (buffer=AllocMem(buffer_size,0)) break;
        buffer_size/=2;
    }

    if (!buffer) goto failed;

    if (!infile && (!(inhandle=Open(src,MODE_OLDFILE)))) goto failed;
    if (!(outhandle=Open(dst,MODE_NEWFILE))) goto failed;

    DateStamp(&ds);

    size_read=size_write=0;
    size_total=size*2;

    while (size>0) {
        readsize=(size>buffer_size)?buffer_size:size;
        if (infile) length=ReadAsync(infile,buffer,readsize);
        else length=Read(inhandle,buffer,readsize);

        size-=readsize;
        size_read+=length;

        if (prog)
            dotaskmsg(hotkeymsg_port,PROGRESS_UPDATE,size_read+size_write,size_total,NULL,1);

        if (status_haveaborted) {
            ret=-1;
            goto failed;
        }

        if (password) {
            int a;
            char enbyte;

            if (encryptstate) {
                for (a=0;a<length;a++) {
                    enbyte=Random(9999);
                    buffer[a]+=enbyte;
                }
            }
            else {
                for (a=0;a<length;a++) {
                    enbyte=Random(9999);
                    buffer[a]-=enbyte;
                }
            }
        }

        if (length>0) {
/*
            if (outfile) {
                if ((WriteAsync(outfile,buffer,length))==-1) goto failed;
            }
            else
*/
            if ((Write(outhandle,buffer,length))==-1) goto failed;
        }
        size_write+=length;
    
        if (prog)
            dotaskmsg(hotkeymsg_port,PROGRESS_UPDATE,size_read+size_write,size_total,NULL,1);

        if (status_haveaborted) {
            ret=-1;
            goto failed;
        }
    }

    if (infile) CloseAsync(infile);
/*
    if (outfile) CloseAsync(outfile);
*/
    if (inhandle) Close(inhandle);
    if (outhandle) Close(outhandle);

    FreeMem(buffer,buffer_size);

    if (config->copyflags&COPY_DATE) {
        setdate(dst,&(cfinfo.fib_Date));
        dsp=&cfinfo.fib_Date;
    }
    else dsp=&ds;
    copy_datestamp(dsp,&dos_copy_date);
    if (config->copyflags&COPY_PROT) SetProtection(dst,cfinfo.fib_Protection);
    dos_copy_protection=cfinfo.fib_Protection;
    if (config->copyflags&COPY_NOTE) {
        SetComment(dst,cfinfo.fib_Comment);
        strcpy(dos_copy_comment,cfinfo.fib_Comment);
    }
    else dos_copy_comment[0]=0;
    return(1);

failed:
    *err=IoErr();
    if (buffer) FreeMem(buffer,buffer_size);
    if (infile) CloseAsync(infile);
    if (inhandle) Close(inhandle);
    if (/* outfile || */ outhandle) {
/*
        if (outfile) CloseAsync(outfile);
        else
*/
        Close(outhandle);
        DeleteFile(dst);
    }
    return(ret);
}

struct Directory *checktot(dir)
struct DirectoryWindow *dir;
{
    struct Directory *first;

    if (!dir) return(NULL);
    first=dir->firstentry;
    while (first) {
        if (first->selected && first->type<=ENTRY_FILE) break;
        first=first->next;
    }
    return(first);
}

struct Directory *checkdirtot(dir)
struct DirectoryWindow *dir;
{
    struct Directory *first;

    if (!dir) return(NULL);
    first=dir->firstentry;
    while (first) {
        if (first->selected && ENTRYTYPE(first->type)==ENTRY_DIRECTORY) break;
        first=first->next;
    }
    return(first);
}

struct Directory *checkdevtot(dir)
struct DirectoryWindow *dir;
{
    struct Directory *first;

    if (!dir) return(NULL);
    first=dir->firstentry;
    while (first) {
        if (first->selected && first->type==ENTRY_DEVICE) break;
        first=first->next;
    }
    return(first);
}

struct Directory *checkalltot(dir)
struct DirectoryWindow *dir;
{
    struct Directory *first;

    if (!dir) return(NULL);
    first=dir->firstentry;
    while (first) {
        if (first->selected && first->type!=ENTRY_DEVICE && first->type!=ENTRY_CUSTOM) break;
        first=first->next;
    }
    return(first);
}

struct Directory *findfile(dir,name,count)
struct DirectoryWindow *dir;
char *name;
int *count;
{
    struct Directory *find;
/*
    char parsebuf[100];

    LParsePatternI(name,parsebuf);
*/

    if (dir) {
        find=dir->firstentry;
        if (count) *count=0;
        while (find) {
/*
            if (find->name && (LMatchPatternI(parsebuf,find->name))) return(find);
*/
            if (find->name && !(LStrCmpI(name,find->name))) return(find);

            find=find->next;
            if (count) ++(*count);
        }
    }
    return(NULL);
}

delfile(name,nam,errs,unprotect,errcheck)
char *name,*nam,*errs;
int unprotect,errcheck;
{
    int suc,a,err,try=0,recplus=0;
    char buf[300],buf2[100];

loop:
    suc=DeleteFile(name);
    if (!suc) {
        if ((err=IoErr())==ERROR_OBJECT_NOT_FOUND) suc=1;
        else {
            if (err==ERROR_DIRECTORY_NOT_EMPTY) return(-2);
            else if (err==ERROR_DELETE_PROTECTED && try==0) {
                if (!(config->deleteflags&DELETE_SET)) {
                    if (!unprotect) {
                        doerror(ERROR_DELETE_PROTECTED);
                        geterrorstring(buf2,ERROR_DELETE_PROTECTED);
                        lsprintf(buf,globstring[STR_ERROR_OCCURED],globstring[STR_DELETING],nam,buf2);
                        strcat(buf,globstring[STR_SELECT_UNPROTECT]);
                        if (!(a=simplerequest(buf,globstring[STR_UNPROTECT],
                            globstring[STR_ABORT],globstring[STR_UNPROTECT_ALL],globstring[STR_SKIP],NULL)))
                            return(-1);
                        if (a==3) return(0);
                        if (a==2) recplus=1;
                    }
                }
                try=1;
                SetProtection(name,0);
                goto loop;
            }
            else if (!errcheck) return(-2);
            doerror(err);
            if ((a=checkerror(errs,nam,err))==3) return(-1);
            if (a==1) goto loop;
        }
    }
    else {
        if (recplus) suc=2;
        else suc=1;
    }
    return(suc);
}

getwildrename(sname,dname,name,newn)
char *sname,*dname,*name,*newn;
{
    char sfirst[40],slast[40],dfirst[40],dlast[40],foon[40];
    int a,b,c,flen,llen,d;

    b=strlen(sname); sfirst[0]=slast[0]=0;
    for (a=0;a<b;a++)
        if (sname[a]=='*') {
            strcpy(sfirst,sname); sfirst[(flen=a)]=0;
            strcpy(slast,(char *)&sname[a+1]);
            llen=b-a;
            break;
        }
    b=strlen(dname);
    for (a=0;a<b;a++)
        if (dname[a]=='*') {
            strcpy(dfirst,dname); dfirst[a]=0;
            strcpy(dlast,(char *)&dname[a+1]);
            break;
        }
    a=strlen(sfirst); b=strlen(slast);
    if ((!a || (LStrnCmpI(name,sfirst,flen))==0) &&
        (!b || ((d=strlen(name))>=llen && (LStrCmpI(&name[(d-llen)+1],slast))==0))) {
        c=strlen(name)-a-b;
        CopyMem((char *)&name[a],foon,c);
        foon[c]=0;
        strcpy(newn,dfirst); strcat(newn,foon); strcat(newn,dlast);
        if (newn[0]!=0) return(1);
    }
    return(0);
}

void filloutcopydata(dir)
struct Directory *dir;
{
    dos_copy_date.ds_Days=dir->date.ds_Days;
    dos_copy_date.ds_Minute=dir->date.ds_Minute;
    dos_copy_date.ds_Tick=dir->date.ds_Tick;
    dos_copy_protection=dir->protection;
    if (dir->comment) strcpy(dos_copy_comment,dir->comment);
    else dos_copy_comment[0]=0;
}

void filloutcopydatafile(fil)
char *fil;
{
    struct FileInfoBlock __aligned fileinfo;

    if (lockandexamine(fil,&fileinfo)) {
        dos_copy_date.ds_Days=fileinfo.fib_Date.ds_Days;
        dos_copy_date.ds_Minute=fileinfo.fib_Date.ds_Minute;
        dos_copy_date.ds_Tick=fileinfo.fib_Date.ds_Tick;
        dos_copy_protection=fileinfo.fib_Protection;
        strcpy(dos_copy_comment,fileinfo.fib_Comment);
    }
}

void update_buffer_stamp(win,true)
int win,true;
{
    struct FileInfoBlock __aligned fib;
    char dirbuf[256];
    struct DirectoryWindow *dirwin;

    if (win==-1 || !(config->dirflags&DIRFLAGS_REREADOLD)) return;

    dirwin=dopus_curwin[win];
    strcpy(dirbuf,str_pathbuffer[win]);
    FOREVER {
        if (true) {
            if (lockandexamine(dirbuf,&fib))
                copy_datestamp(&fib.fib_Date,&dirwin->dirstamp);
            if (!(doparent(dirbuf)) ||
                !(dirwin=findbuffer(dirbuf,win,0,1))) break;
        }
        else {
            if (!(dirwin=dirwin->next) ||
                dirwin==dopus_curwin[win]) break;
            if (LStrnCmpI(dirwin->directory,dirbuf,strlen(dirbuf))==0) {
                dirwin->dirstamp.ds_Days=0;
                dirwin->dirstamp.ds_Minute=0;
                dirwin->dirstamp.ds_Tick=0;
            }
        }
    }
}

check_key_press(func,code,qual)
struct dopusfunction *func;
USHORT code,qual;
{
    if (!func->function ||
        !func->function[0] ||
        (func->key==0xff && func->qual==0) ||
        func->key==0 ||
        func->qual!=qual) return(0);
    if (func->key==0xff || func->key==code) return(1);
    return(0);
}
