/* apccomm_am.c
   Part of "APCComm" 
   Copyright (C) 2001 Ralf Hoffmann
   Contact: ralf.hoffmann@epost.de

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.
  
*/
/* $Id: apccomm_am.c,v 1.6 2001/08/26 00:29:17 ralf Exp $ */

#include "apccomm_am.h"
#include "apccomm_am_tr.h"
#include "apccomm_all.h"

struct transfer_log tfl;

int sendRec(const char *fullname, struct FileInfoBlock *fib, int root)
{
  struct FileInfoBlock rfib;
  BPTR lck,plck;
  char *rfn;
  int ret=0;
  apc_command_t com;
  LONG prot;

  if(fib->fib_DirEntryType < 0) {
    /* a file
       send it with name fib_FileName (not needed)
       open it with fullname */
    ret=sendcommand(APC_COMMAND_FILETRANSFER,fullname,fib->fib_Protection);
  } else {
    /* Lock the dir for Examine */
    lck = Lock(fullname, ACCESS_READ);
    if(lck != NULL) {
      if(Examine(lck, &rfib)) {

        /* Verzeichnis "fullname" wird geentert
           Also "Create&Enter Senden
           Wenn aber root==1, dann stellt "fullname" das Basisverz.
           dar */

	/* Send "Create&Enter" for rfib.fib_FileName */
	
	/* If root==1 it's possibly that this dir is an root-dir (device)
	 * to detect I try to get a parent lock
	 * I know that fib_DirEntryType should be 1 in this case but this
	 * doesn't work correctly for some (many devices) (f.i. disk drives)
	 *
	 * I do this because for root-dirs the fib_Protection doesn't have
	 * useful values
	 */
	if ( root == 1 ) {
	  plck = ParentDir( lck );
	  if ( plck != NULL ) {
	    /* not a root dir */
	    prot = rfib.fib_Protection;
	    UnLock( plck );
	  } else prot = 0; /* normal dir protection */
	} else prot = rfib.fib_Protection;
	ret = sendcommand( APC_COMMAND_ENTERDIR, rfib.fib_FileName, prot );
	com = (apc_command_t) getint(inblock);
	if ( com == APC_COMMAND_ABORT ) ret = -1;

	if(ret==0) {
	  while(ExNext(lck, &rfib)) {
	    rfn = (char*)malloc( strlen(fullname)+1+
				 strlen(rfib.fib_FileName)+1);
	    if(rfn!=NULL) {
	      if(fullname[strlen(fullname)-1] == ':') {
		sprintf(rfn, "%s%s", fullname, rfib.fib_FileName);
	      } else {
		sprintf(rfn, "%s/%s", fullname, rfib.fib_FileName);
	      }
	      ret=sendRec(rfn, &rfib, 0);
	      free(rfn);
	      if(ret!=0) break;
	    } else {
	      printf("No mem!\n");
	    }
	  }
	  if ( ret == 0 ) {
	    /* Send: cd.. (nur wenn root==0?) */
	    ret = sendcommand( APC_COMMAND_LEAVEDIR, NULL , 0 );
	    com = (apc_command_t) getint(inblock);
	    if ( com == APC_COMMAND_ABORT ) ret = -1;
	  }
	}
      }
      UnLock(lck);
    } else {
      printf("No lock for %s, skipping!\n",fullname);
    }
  }
  return ret;
}

int send(int argc,char **argv,short *realargs)
{
  struct AnchorPath *ap;
  int i;
  int err,ret=0;
  ULONG secs, usecs;
  double d1;

  /* Get the space for the structure plus enough for full pathname
     provided by AmigaOS when ap_Strlen>0 */
  ap = (struct AnchorPath*)malloc(sizeof(struct AnchorPath)+1048);
  if(ap == NULL) return 1;

  /* clear the structure */
  memset(ap, 0, sizeof(struct AnchorPath));

  ap->ap_Strlen = 1024;
  /*ap->ap_BreakBits = 0;*/

  /* init transfer log */
  tfl.files = 0;
  tfl.bytes = 0;
  tfl.secs = tfl.usecs = 0;

  /* for all args */
  for( i = 1; i < argc; i++ ) {
    /* only if this arg should be used
     * determined by the options-checker in main
     */
    if(realargs[i] == 1) {
      /* Now find all files (for pattern matching) */
      if((err=MatchFirst(argv[i],ap))==0) {
	do {
          /* now send the entry (can be a file or a dir) */
	  ret = sendRec( ap->ap_Buf, &(ap->ap_Info), 1 );
	  if ( ret < 0 ) break;
	} while(MatchNext(ap)==0);
	MatchEnd(ap);
      } else {
        if(err==ERROR_OBJECT_NOT_FOUND) {
	  printf("No matching files found!\n");
	} else {
	  printf("Error %d while matching given pattern!\n",err);
	}
      }
    }
  }
  free(ap);
  if ( ret == 0 ) {
    sendcommand(APC_COMMAND_FINISHED,NULL,0);
    
    if ( ! BE_QUIET ) printf("Whole transfer completed!\n");

    if ( tfl.files > 1 ) {
      secs = tfl.secs;
      usecs = tfl.usecs;
      if ( ( secs == 0 ) && ( usecs == 0 ) ) d1 = 0.0;
      else {
	d1=tfl.bytes;
	d1*=1000000;
	d1/=(secs*1000000.0+usecs);
	d1/=1024;
      }
      if ( ! BE_QUIET ) {
	printf( "  Files sended: %ld\n", tfl.files );
	printf( "  Bytes with average rate: %ld @ %d KB/s\n", tfl.bytes, (int)d1 );
      }
    }
  } else {
    printf( "Transfer aborted!\n" );
  }
  return 0;
}

int receive()
{
  char *arg,*tstr,*tstr2;
  apc_command_t com;
  int ret=0;
  BPTR lock;
  struct FileInfoBlock infoBlock;
  ULONG secs, usecs;
  double d1;
  int mode;

  /* init transfer log */
  tfl.files = 0;
  tfl.bytes = 0;
  tfl.secs = tfl.usecs = 0;

  basedir=NULL;
  do {
    if(recvcommand(&com,&arg,&mode)==0) {
      if(com==APC_COMMAND_ENTERDIR) {
	if(arg!=NULL) {
	  if(basedir==NULL) {
	    basedir=(char*)malloc(strlen(arg)+1+1);
	    sprintf(basedir,"%s/",arg);
	    free(arg);
	  } else {
	    tstr=(char*)malloc(strlen(basedir)+strlen(arg)+1+1);
	    sprintf(tstr,"%s%s/",basedir,arg);
	    free(basedir);
	    basedir=tstr;
	    free(arg);
	  }
	  /* now create basedir */
	  tstr2=strrchr(basedir,'/');
	  *tstr2='\0';
	  if(strlen(basedir)!=0) {
	    /* test for existing entry */
	    lock=Lock(basedir,ACCESS_READ);
	    if(lock==NULL) {
	      /* no? then try to create a dir */
	      lock=CreateDir(basedir);
	      if(lock==NULL) {
		/* No sucess? -> Return */
		printf( "Can't create dir %s!\n", basedir );
		ret=1;
		break;
	      } else UnLock(lock); /* Succes, just unlock */
	    } else {
	      /* Something exists there, get some info about it */
	      if(Examine(lock,&infoBlock)==0) {
		/* no info? -> return */
		printf( "Can't get information about %s, aborting!\n", basedir );
		ret=1;
		UnLock(lock);
		break;
	      } else {
		if(infoBlock.fib_DirEntryType<0) {
		  /* this is a file -> return */
		  printf( "Want to create dir %s, but it's already a file, aborting!\n", basedir );
		  ret=1;
		  UnLock(lock);
		  break;
		}
	      }
	      /* Ok, there is already a dir */
	      UnLock(lock);
	    }
	    /* Apply mode to dir */
	    if ( ! ignore_prot )
	      if ( SetProtection( basedir, mode ) == 0 )
		printf( "Can't restore file protection to %s\n", basedir );

	  }
	  *tstr2='/';
	}
      } else if(com==APC_COMMAND_LEAVEDIR) {
	if(basedir!=NULL) {
	  if(basedir[strlen(basedir)-1]==':') {
	    free(basedir);
	    basedir=NULL;
	  } else {
	    tstr=strrchr(basedir,'/');
	    *tstr='\0';
	    tstr=strrchr(basedir,'/');
	    if(tstr!=NULL) {
	      *(tstr+1)='\0';
	    } else {
	      tstr=strrchr(basedir,':');
	      if(tstr!=NULL) {
		*(tstr+1)='\0';
	      } else {
		free(basedir);
		basedir=NULL;
	      }
	    }
	    if(basedir!=NULL)
	      if(strlen(basedir)<1) {
		free(basedir);
		basedir=NULL;
	      }
	  }
	}
      } else if(com==APC_COMMAND_FILETRANSFER) {
	/* Nothing has to be done because recvcommand handle this already */
      } else if(com==APC_COMMAND_ERROR) {
	break;
      } else if ( com == APC_COMMAND_ABORT ) {
	break;
      }
    } else {
      printf( "Transfer aborted\n" );
      break;
    }
  } while(com!=APC_COMMAND_FINISHED);

  if ( ret == 0 ) {
    if ( ! BE_QUIET ) printf("Whole transfer completed!\n");
    
    if ( tfl.files > 1 ) {
      secs = tfl.secs;
      usecs = tfl.usecs;
      if ( ( secs == 0 ) && ( usecs == 0 ) ) d1 = 0.0;
      else {
	d1=tfl.bytes;
	d1*=1000000;
	d1/=(secs*1000000.0+usecs);
	d1/=1024;
      }
      if ( ! BE_QUIET ) {
	printf( "  Files received: %ld\n", tfl.files );
	printf( "  Bytes with average rate: %ld @ %d KB/s\n", tfl.bytes, (int)d1 );
      }
    }
  } else {
    sendcommand( APC_COMMAND_ABORT, NULL , 0 );
  }

  return ret;
}

int permAmiga2PC(int perm)
{
  int pcperm=0;
  
  /* For DELETE/EXECUTE/WRITE/READ:
   * If set it's forbidden!
   */

  if ( ! ( perm & FIBF_DELETE ) ) pcperm |= 0040;
  if ( ! ( perm & FIBF_EXECUTE ) ) pcperm |= 0100;
  if ( ! ( perm & FIBF_WRITE ) ) pcperm |= 0200;
  if ( ! ( perm & FIBF_READ ) ) pcperm |= 0400;
  if ( perm & FIBF_PURE ) pcperm |= 0001;
  if ( perm & FIBF_SCRIPT ) pcperm |= 0004;
  if ( perm & FIBF_ARCHIVE ) pcperm |= 0010;
  
  return pcperm;
}

int permPC2Amiga(int perm)
{
  int amperm=0;
  
  if ( ! ( perm & 0400 ) ) amperm |= FIBF_READ;
  if ( ! ( perm & 0200 ) ) amperm |= FIBF_WRITE;
  if ( ! ( perm & 0100 ) ) amperm |= FIBF_EXECUTE;
  if ( ! ( perm & 0040 ) ) amperm |= FIBF_DELETE;
  if ( perm & 0010 ) amperm |= FIBF_ARCHIVE;
  if ( perm & 0004 ) amperm |= FIBF_SCRIPT;
  if ( perm & 0001 ) amperm |= FIBF_PURE;

  return amperm;
}
