
/* Remote.c By Kamran Karimi 
   Part of EasyAmiga source.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <stat.h>

#include <exec/types.h>
#include <dos.h>
#include <clib/dos_protos.h>

#include "ErrCodes.h"

#define min(a,b) (a) <= (b) ? (a) : (b)

#define QUIT 49
#define DIR 50
#define CD 51
#define RECEIVE 52
#define SEND 53
#define MKDIR 54
#define RMDIR 55
#define DELETE 56
#define CHECKLINK 57

#define MAXNAME 200

#define SERTESTLEN 255

#define BIOS 0
#define HARD 1

extern long OverWriteProtect;
extern long NumDone;

extern VOID ShowRemainder(ULONG Transfered, ULONG Total);
extern VOID PrintFileName(char *Name);
extern LONG ReceivePacket(VOID),SendPacket(VOID),ConfigSerial(ULONG BAUD);
extern struct FInfo *First[2];
extern USHORT FileNum[2];

extern VOID AddToList(struct FInfo *finfo,int list);

extern LONG GetSynch(VOID),PutSynch(VOID);
extern LONG PutError(long ErrNo);


extern SHORT Mode;
extern SHORT CurrSpeed;
extern SHORT Method;

extern size_t FileBuffSize;

struct FInfo  {
 struct FInfo *next,*prev;
 byte Selected,type;
 char name[32];
 char data[MAXAMINFOLEN + 10];
};


extern ULONG Speed[MAXHARDSPEED];

ULONG WorkstationWait[MAXHARDSPEED] = 
  { 30, 60, 120, 240, 480, 960, 1920, 3840, 5760, 11520 }; 


ULONG ErrorCode;    /* global error code */

union ReceiveUnion
{
 ULONG Len;
 UBYTE Char[4];
};

union ReceiveUnion Receive;

#define PACKET_SIZE 255

struct PacketStruct
{
 UBYTE Len;
 UBYTE Data[PACKET_SIZE + 2];
};

struct PacketStruct Packet;


LONG ReceiveFile(VOID);


LONG ReceiveDirectory(VOID)
{
 LONG Error;
 UBYTE len,Name[MAXNAME];
 
 if((Error = PutSynch())) return Error;
 Packet.Len = 1;
 if((Error = ReceivePacket())) return Error; 
 len = Packet.Data[0];
 if((Error = PutSynch())) return Error;
 Packet.Len = len;
 if((Error = ReceivePacket())) return Error;
 Packet.Data[len] = NULL;
 strcpy(Name,Packet.Data);
 if(mkdir(Name)) { PutError(ERROR_LocMKDir); return ERROR_LocMKDir; }
 if(chdir(Name)) { PutError(ERROR_LocCHDir); return ERROR_LocCHDir; }
 if((Error = PutSynch())) return Error;
 NumDone++;
 do
 {
  Packet.Len = 1;
  if((Error = ReceivePacket())) { chdir("/"); return Error; }
  if(Packet.Data[0] == 'E') break;
  else if(Packet.Data[0] != '!') { chdir("/"); return ERROR_Direc; } 
   if((Error = ReceiveFile())) { chdir("/"); return Error; }
 }while(TRUE);
 if((Error = PutSynch())) { chdir("/"); return Error; } 
 if((Error = GetSynch())) { chdir("/"); return Error; } 
 chdir("/"); 
 return NO_ERROR;
}
    
 /* create a file with the name "Name" and copies 
    Receive.Len bytes to it */
LONG ReceiveFile(VOID)
{
 LONG Error,index,count,TotalLen;
 FILE  *file;
 UBYTE len;
 char Name[MAXNAME],TransBuff[PACKET_SIZE];

 PrintFileName(NULL);
 ShowRemainder(0,0);
 if((Error = PutSynch())) return Error;
 Packet.Len = 1;
 if((Error = ReceivePacket())) return Error;
 if(Packet.Data[0] == 'D') 
  return ReceiveDirectory();
 else if(Packet.Data[0] != 'F') return ERROR_RecFile;
 if((Error = PutSynch())) return Error;
 Packet.Len = 4;
 if((Error = ReceivePacket())) return Error;
 for(count = 3; count >= 0; count--)
  Receive.Char[count] = Packet.Data[count];
 if((Error = PutSynch())) return Error;
 Packet.Len = 1;
 if((Error = ReceivePacket())) return Error;
 len = Packet.Data[0]; 
 if((Error = PutSynch())) return Error;
 Packet.Len = len;
 if((Error = ReceivePacket())) return Error;
 Packet.Data[len] = NULL;
 strcpy(Name,Packet.Data);
 if(OverWriteProtect == TRUE)
 {
  if((file = fopen(Name,"r")))
  { PutError(ERROR_GFExists); fclose(file); return ERROR_GFExists; }
 }
 if((file = fopen(Name,"wb"))== NULL) 
 { PutError(ERROR_GetFile); return ERROR_GetFile; }
 if((Error = PutSynch())) { fclose(file); return Error; }
 if((Error = GetSynch())) { fclose(file); return Error; }
 setvbuf(file,NULL,_IOFBF,FileBuffSize); 
 PrintFileName(Name);
 TotalLen = Receive.Len;
 while(Receive.Len > 0)
 {
  len = min(Receive.Len,PACKET_SIZE);
  Receive.Len -= len;
  Packet.Len = 1;
  Packet.Data[0] = len;
  if((Error = SendPacket())) { fclose(file); return Error; }
  Packet.Len = len;
  if((Error = ReceivePacket())) { fclose(file); return Error; }
  ShowRemainder(TotalLen - Receive.Len,TotalLen); 
  index = 0;
  for(count = 0; count < Packet.Len; count++)
  { 
   if((Mode == TEXT) && ((Packet.Data[count] == 13) || 
                                  (Packet.Data[count] == 26)))
    continue;
   TransBuff[index++] = Packet.Data[count];
  }
  if(fwrite(TransBuff,1,index,file) != index)
   { fclose(file); return ERROR_Write; } 
 }
 fclose(file);
 NumDone++;
 return NO_ERROR;
} 
 

LONG EstablishConnection(VOID)
{
 LONG Error;

 if((Error = PutSynch())) return Error;
 if((Error = GetSynch())) return Error;
 return NO_ERROR;
}

LONG SendCMDLen(UBYTE CMDLen)
{
 LONG Error;

 if((Error = EstablishConnection())) return Error;
 Packet.Len= 1;
 Packet.Data[0] = CMDLen;
 if((Error = SendPacket())) return Error;
 if((Error = GetSynch())) return Error;
 else return NO_ERROR;
} 

LONG RemoteReceive(VOID)
{
 struct FInfo *tmp;
 LONG FNameLen,count,Error;

 NumDone = 0; 
 for(tmp = First[PC]; tmp; tmp = tmp->next)
 {
  if(tmp->Selected)
  {
   FNameLen = strlen(tmp->name);
   if((Error = SendCMDLen(1 + FNameLen))) return Error;
   Packet.Len = 1 + FNameLen;
   Packet.Data[0] = RECEIVE;
   for(count = 1; count <= FNameLen; count++)
    Packet.Data[count] = tmp->name[count - 1];
   if((Error = SendPacket())) return Error;
   if((Error = GetSynch())) return Error;
   if(Error = ReceiveFile()) return Error;
  }
 }
 return NO_ERROR;
} 


LONG RemoteMKDir(char *Name)
{
 LONG Error,count,DNameLen = strlen(Name);

 NumDone = 0;
 if((Error = SendCMDLen(1 + DNameLen))) return Error;
 Packet.Len = 1 + DNameLen;
 Packet.Data[0] =  MKDIR; 
 for(count = 1; count <= DNameLen; count++)
  Packet.Data[count] = Name[count - 1];
 if((Error = SendPacket())) return Error;
 Packet.Len = 1;
 if((Error = ReceivePacket())) return Error;
 if(Packet.Data[0] != '!') return ERROR_MKDIR;
 NumDone = 1;
 return NO_ERROR;
}

LONG SendFile(char *Name);


LONG HandleDirSend(char *Name)
{
 LONG Error,count;
 __aligned
 struct FileInfoBlock info;

 Packet.Len = 1;
 Packet.Data[0] = 'D';
 if((Error = SendPacket())) return Error;
 if((Error = GetSynch())) return Error;
 Packet.Len = 1;
 Packet.Data[0] = strlen(Name);
 if((Error = SendPacket())) return Error;
 if((Error = GetSynch())) return Error;
 for(count = 0; count < strlen(Name); count++)
  Packet.Data[count] = Name[count];
 Packet.Len = strlen(Name); 
 if((Error = SendPacket())) return Error;
 if((Error = GetSynch())) return Error;
 if(chdir(Name)) return ERROR_LocCHDir;
 NumDone++;
 if(dfind(&info,"#?",1)) 
 {
  Packet.Len = 1;
  Packet.Data[0] = 'E';
  if((Error = SendPacket())) { chdir("/"); return Error; }
  if((Error = GetSynch())) { chdir("/"); return Error; }
  chdir("/");
  return NO_ERROR;
 }
 do
 {
  if((Error = PutSynch())) { chdir("/"); return Error; }
  if((Error = GetSynch())) { chdir("/"); return Error; }
  if(info.fib_DirEntryType > 0) 
  { 
   if((Error = HandleDirSend(info.fib_FileName))) 
   { chdir("/"); return Error; }
  }
  else
  if((Error = SendFile(info.fib_FileName))) { chdir("/"); return Error; }
 }while(!dnext(&info));
 Packet.Len = 1;
 Packet.Data[0] = 'E';
 if((Error = SendPacket())) { chdir("/"); return Error; }
 if((Error = GetSynch())) { chdir("/"); return Error; }
 chdir("/");
 return NO_ERROR;
} 

LONG SendFile(char *Name)
{
 LONG Error,count,TotalLen,Transfered = 0;
 FILE *file;
 UBYTE len;
 struct stat st;
 char TempName[36];

 PrintFileName(NULL);
 ShowRemainder(0,0);
 strcpy(TempName,Name);
 if(TempName[0] == '.') TempName[0] = '_'; 
 if((file = fopen(Name,"rb")) == NULL) return ERROR_SendFile;
 setvbuf(file,NULL,_IOFBF,FileBuffSize); 
 if(fstat(fileno(file),&st)) { fclose(file); return ERROR_Stat; }
 PrintFileName(Name);
 Packet.Len = 1;
 if(Mode == TEXT) Packet.Data[0] = 'T';
 else Packet.Data[0] = 'B';
 if((Error = SendPacket())) { fclose(file); return Error; }
 if((Error = GetSynch())) { fclose(file); return Error; }
 if(OverWriteProtect == TRUE) Packet.Data[0] = 'P';
 else Packet.Data[0] = 'O';
 if((Error = SendPacket())) { fclose(file); return Error; }
 if((Error = GetSynch())) { fclose(file); return Error; }
 Packet.Len = 1;
 Packet.Data[0] = strlen(Name);
 if((Error = SendPacket())) { fclose(file); return Error; }
 if((Error = GetSynch())) { fclose(file); return Error; }
 for(count = 0; count < strlen(Name); count++)
  Packet.Data[count] = TempName[count];
 Packet.Len = strlen(Name);
 if((Error = SendPacket())) { fclose(file); return Error; }
 if((Error = GetSynch())) { fclose(file); return Error; }
 Receive.Len = st.st_size;
 TotalLen = Receive.Len;
 for(count = 3; count >= 0; count--)
  Packet.Data[count] = Receive.Char[3 - count];
 Packet.Len = 4;
 if((Error = SendPacket())) { fclose(file); return Error; }
 Transfered = 0;
 while((TotalLen - Transfered) > 0)
 {
  Packet.Len = 1;
  if((Error = ReceivePacket())) { fclose(file); return Error; }
  len = Packet.Data[0];
  if(fread(Packet.Data,1,len,file) != len)
   { fclose(file); return ERROR_Read; }
  Packet.Len = len;
  if((Error = SendPacket())) { fclose(file); return Error; }
  Transfered += len;
  ShowRemainder(Transfered,TotalLen);
 }
 if((Error = GetSynch())) { fclose(file); return Error; } 
 fclose(file);
 NumDone++;
 return NO_ERROR;
}


LONG RemoteSend(VOID)
{
 struct FInfo *tmp;
 LONG Error;
 
 NumDone = 0;
 for(tmp = First[AM]; tmp; tmp = tmp->next)
 {
  if(tmp->Selected)
  {
   if((Error = SendCMDLen(1))) return Error;
   Packet.Len = 1;
   Packet.Data[0] =  SEND;
   if((Error = SendPacket())) return Error;
   if((Error = GetSynch())) return Error;
   if(tmp->type == DIRTYPE)  
   { if((Error = HandleDirSend(tmp->name))) return Error; }
   else if((Error = SendFile(tmp->name))) return Error;
  }
 }
 return NO_ERROR;
}

LONG RemoteDelFile(char *Name)
{
 LONG Error,count,FNameLen = strlen(Name);
 
 if((Error = SendCMDLen(1 + FNameLen))) return Error;
 Packet.Len = 1 + FNameLen;
 Packet.Data[0] =  DELETE;
 for(count = 1; count <= FNameLen; count++)
  Packet.Data[count] = Name[count - 1];
 if((Error = SendPacket())) return Error;
 if((Error = GetSynch())) return Error;
 return NO_ERROR;
}


LONG RemoteDelDir(char *Name)
{
 LONG Error,count,DNameLen = strlen(Name);

 if((Error = SendCMDLen(1 + DNameLen))) return Error;
 Packet.Len = 1 + DNameLen;
 Packet.Data[0] =  RMDIR; 
 for(count = 1; count <= DNameLen; count++)
  Packet.Data[count] = Name[count - 1];
 if((Error = SendPacket())) return Error;
 if((Error = GetSynch())) return Error;
 return NO_ERROR;
}

LONG RemoteDel(VOID)
{
 struct FInfo *tmp;
 
 NumDone = 0;
 for(tmp = First[PC]; tmp; tmp = tmp->next)
 {
  if(tmp->Selected)
  {
   if(tmp->type == FILETYPE) 
   { if(RemoteDelFile(tmp->name)) return ERROR_FDelete; }
   else 
   { if(RemoteDelDir(tmp->name)) return ERROR_RMDIR; }
   NumDone++; 
  }
 }
 return NO_ERROR;
}


LONG RemoteCd(char *Path)
{
 LONG Error,result = NO_ERROR,count,PathLen = strlen(Path);
 char temp;

 NumDone = 0;
 if((Error = SendCMDLen(1 + PathLen))) return Error;
 Packet.Len = 1 + PathLen;
 Packet.Data[0] =  CD;
 for(count = 1; count <= PathLen; count++)
  Packet.Data[count] = Path[count - 1];
 if((Error = SendPacket())) return Error;
 Packet.Len = 1;
 if((Error = ReceivePacket())) return Error;
 if(Packet.Data[0] != '!') result = ERROR_CHDIR;
 if((Error = PutSynch())) return Error;
 Packet.Len = 1;
 if((Error = ReceivePacket())) return Error;
 count = Packet.Data[0];
 if((Error = PutSynch())) return Error;
 Packet.Len = count;
 if((Error = ReceivePacket())) return Error;
 temp = Packet.Data[0];
 if((Error = PutSynch())) return Error;
 if((Error = GetSynch())) return Error;
 Packet.Data[0] = temp;
 Packet.Data[count] = NULL; 
 NumDone = 1;
 return result;
}

LONG RemoteQuit(VOID)
{
 LONG Error;

 NumDone = 0;
 if((Error = SendCMDLen(1))) return Error;
 Packet.Len = 1;
 Packet.Data[0] =  QUIT;
 if((Error = SendPacket())) return Error;
 NumDone = 1;
 return NO_ERROR;
}

LONG RemoteDir(VOID)
{
 LONG Error,count;
 struct FInfo *finfo;
 UBYTE NextLineLen;

 NumDone = 0;
 if((Error = SendCMDLen(1))) return Error;
 Packet.Len = 1;
 Packet.Data[0] =  DIR;
 if((Error = SendPacket())) { return Error; }
 while(TRUE)
 {
  Packet.Len = 1;
  if((Error = ReceivePacket())) { return Error; }
  NextLineLen = Packet.Data[0];
  if((Error = PutSynch())) { return Error; }
  if(NextLineLen == 0) break;
  Packet.Len = NextLineLen;
  if((Error = ReceivePacket())) return Error; 
  finfo = malloc(sizeof(struct FInfo));
  if(!finfo) return ERROR_NOMEM;
  Packet.Data[NextLineLen] = NULL;
  strcpy(finfo->data,Packet.Data);
  if(finfo->data[0] == 'D')
   finfo->type = DIRTYPE;
  else 
   finfo->type = FILETYPE;
  finfo->data[0] = ' ';
  for(count = 10; count < 22; count++)
   finfo->name[count - 10] = Packet.Data[count];
  for(count = 11; count >= 0; count--)
  {
   if(finfo->name[count] == ' ') finfo->name[count] = NULL;
   else break;
  } 
  finfo->name[12] = NULL;
  if(!First[PC]) FileNum[PC] = 1;
  else FileNum[PC]++;
  AddToList(finfo,PC);
  if((Error = PutSynch())) return Error;
 }
 if((Error = GetSynch())) return Error; 
 NumDone = 1;
 return NO_ERROR;
}

