/*->c.vxcet */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>

#include "h.os"
#include "h.wimp"
#include "h.bbc"
#include "h.flex"


#include "h.wos"
#include "h.timex"

#include "h.main"
#include "h.ram"
#include "h.mym"
#include "h.serial"
#include "h.batch"
#include "h.ftp"
#include "h.view"
#include "h.term"
#include "h.key"

#include "h.vxdef"
#include "h.vxwimp"
#include "h.vxterm"
#include "h.vxsend"


#include "h.vxcet"


/***************************************************************************/
/*
   CET Telesoftware
*/
/*****************************************************************************/



/*****************************************************************************/
           /**********   Telesoftware Downloader *********/

static int shift;                     /* decoder shift */
static int save_shift;                /* copy of ...   */
static int total_blocks;              /* total number of frames in this file */
static int current_block;             /* blocks so far */
static int frame;                     /* the frame letter we're looking for  */
static int wasgood_frame;             /* are we looking for a frame letter   */
static int this_frame;                /* the letter of this frame            */
static int good_frame;                /* did this frame have a |G seq. on it */
static int check;                     /* checksum */
static int tstx;
static int tsty;
static int tsretry;
static int tsover;
static int tseol;                     /* last code was eol */

static FILE * tsfp;                   /* file we write to */

static char lastframe[24];            /* save last good frame we saw */



void tssaveframeref(void)
{
 int i=0;

 if(vscr->tcbuf[0][25]>='0' && vscr->tcbuf[0][25]<='9')
 {
  for(i=0;i<15;i++) lastframe[i]=vscr->tcbuf[0][25+i];
 }

 lastframe[i]=0;
}



/* move to next frame # or 0 */

static void tsnext(void)  
{ 
 if(frame=='a') viewline('0');
 else           viewline(95);
}


/* go back a frame */

static void tsprev(void)
{
 viewline('*');
 viewline(95);
}




/* repeat the current frame */

static void tsrepeat(void)
{
 viewline('*');
 viewline('0');
 viewline('0');
}



/* actually get frame time delays etc. */

static void tsgetframe(void)
{
 int time;
 int byte;
 int bar;
 int cls;

 time=clock()+(800+1000*vxslotel);
 cls=bar=0;

 while(clock()<time && ftp_ok)
 {
  if((byte=getbyte())!=-1)
  {
   tty(byte);
   time=clock()+(500 + 1000*vxslotel);
  }
  else pollzt();


  byte=byte & 0x7F;
  if(byte=='Z' && bar) break;
  else 
  if(byte==12)  cls=1;
  else
  if(byte=='|') bar=1;
  else          bar=0;

  if(ttvy>=22 && cls) break;
 }
    
 do
 {
  byte=getbyte();
  if(byte!=-1)
  {
   tty(byte);
   time=clock()+(50+200*vxslotel);
  }
  else pollzt();
 } while(clock()<time && ftp_ok);
}




static void scanstart(void)
{
 tstx=0;
 tsty=0;
 good_frame=0;
 this_frame='b';
}




static int scannext(void)
{ 
 if(++tstx==40)
 {
  tstx=0;
  if(++tsty==24) return(-1);
 }
 return(0);
}




/* get next character return -1 on eop */

static int tscan(void) 
{
 int i;
 i=vscr->tcbuf[tsty][tstx] & 0x7F;
 check=check ^ i;
 if(scannext()) return(-1); 
 else           return(i);
}




int shiftab[6] = {0,-64,64,96,128,160};



/* get next character 0-255, -1 failed, >255 ?control */

static int scana(void)
{
 int i;

 tseol=0;

 i=tscan();
 if(i<0) return(i);

 if(i==125) return(32);

 if(i!='|') return((shift+i) & 0xFF);

 i=tscan();
 if(i<0) return(i);

 switch(i)
 { 
  case 'L':
           tseol=1;
           return(13);

  case 'F':
           tsover=1;
           return(255);

   case 'E':
            return('|');

   case 125:
            return(125);

   case '0':
   case '1':
   case '2':
   case '3':
   case '4':
   case '5':
            shift=shiftab[i-'0'];
            return(scana());

   default :
            return(256+i);   /* unknown control */
 }
}






/* as scana but mop up a few more control codes */

static int scanb(void)
{
 int i;
  
 i=scana();
  
 if(i<256) return(i);

 if(i=='Z'+256)                  /* end of data */
 {                          
  check=check ^ 'Z';
  check=(check ^ '|') & 0xFF;
  return(i);
 }

 if(i=='G'+256)                  /* frame letter */
 {
  i=scana();
  if(i<0) return(i);
  this_frame=(i-shift) & 0xFF;
  good_frame=1;
 }

 while(1)                        /* detecting |X ... |I sequences */
 {
  i=scana();
  if(i<0) return(i);
  if(i==256+'I') return(scanb());
 }
}





/* scan for first character */

static int scanfirst(void)
{
 int i;

 while(1)
 {
  i=scana();
  if(i<0) return(i);
  if(i=='A'+256) break;
 }

 check=0;
 return(0);
}





static int tsgetnum(void)
{
 char string[12];
 int i;
 int j;

 i=0;
 do
 {
  j=scanb();

  if(j<0 || j>255) break;
  j=(j-shift) & 0xFF;
  string[i]=j;
  if(j<'0' || j>'9') break;

 } while(i++<12);

 string[i]=0;
 sscanf(string,"%d",&i);
 return(i);
}




static void tshehe(void)
{
 tsretry--;
 tsrepeat();
 ftpretinc();
}



/* do a check sum on this frame */
/* return 0 if OK -1 if bad */

static int checksum(void)
{
 int i;
 int oldcheck;
  
 scanstart();

 i=scanfirst();
 if(i<0) return(i);

 while(1)
 {
  i=scanb();
  if(i<0) return(i);
  if(i!='Z'+256) continue;
  oldcheck=check;
  return((oldcheck==tsgetnum())-1);
 }
}



/* do a download from this frame */
/* returns */
/* 0 OK */
/* 1 retried out */
/* 2 can't find header */
/* 3 lost synch        */
/* 4 canned */



static int tsdownload(void)
{
 char outbuff[1024];
 char filename[24];
 char eolsq[24];
 int  eollen;
 int  tsbytes;
 int  i;
 int  j;       
 int  len;
 int  flags;
 int  bn;
 int  noskip;

 shift=0;
 save_shift=0;   
 total_blocks=0; 
 current_block=1;

 convert(vxceteol,eolsq,&eollen,24);

 tsretry=10;
 while(1)
 { 
  if(checksum()==0) break;
  tshehe();
  if(tsretry==0) return(1);
  if(!ftp_ok) return(4);
  tsgetframe();
 }


 scanstart();
 if(scanfirst()<0) return(2);
 i=0;

 do
 {
  j=scanb();
  if(j!=13) j=(j-shift) & 0xFF;
  filename[i]=j;
  if(filename[i]==13) break;
 } while(++i<20);

 if(i>9) i=10;
 filename[i]=0;
 
 len=0;

 tsover=0;
 total_blocks=tsgetnum();
 

 if(vxautoresume) flags=FTPOPENRESUME;

 if((tsfp=ftpopenwrite(filename,&bn,total_blocks,
                                  0,&flags,NULL))==NULL) return(5);

 if((flags & FTPOPENRESUME) && strlen(vtable[RXBFILE][bn].info))
 {
  ftpwritefseek(tsfp,0,SEEK_END);
  vxgoframeref(vtable[RXBFILE][bn].info);
  wasgood_frame=0;
  noskip=0;
 }
 else
 {
  frame=this_frame+1;
  wasgood_frame=good_frame;
  tsnext();
  noskip=1;
 }


 tsretry=10;

 while(1)
 {
  pollzt();
  if(!ftp_ok) return(4);

  tsover=0;
  tsgetframe();

  if(checksum()==0)
  {

      /*
        dprintf("wasgood_frame=%d good_frame=%d this_frame=%d frame=%d",
                                 wasgood_frame,good_frame,this_frame,frame);
      */

   if(wasgood_frame && good_frame && this_frame!=frame)
   {                                                  /* this frame is not the
                                                          one we want */
                                                       /* panic !!! */
    i=this_frame-frame;                          
    if(i<-13 || (i>0 && i<13))
    {
     if(i<0) i+=26;
     if(i>3) return(3);
     tsprev();
    }
    else 
    {
     if(this_frame=='z') viewline('0');
     else                viewline(95);
    }

   }
   else
   {
    /* everything OK */
    scanstart();

    if(vxcetel) shift=save_shift;
    else        shift=0;   

    tsbytes=0;
    i=scanfirst();
    while(1)
    {                        /* dump bytes to file loop */
     i=scanb();
     if(i<0 || i>255) break;

     if(tseol && eollen) 
        for(i=0;i<eollen;i++) outbuff[tsbytes++]=eolsq[i];
     else                     outbuff[tsbytes++]=i;
    }

    if(noskip) ftpwrite(outbuff,1,tsbytes,tsfp);
    noskip=1;

    ftpbloinc();
    tssaveframeref();



    if(ftpwriteerror(tsfp)) return(5);

    save_shift=shift;
    current_block++;

    wasgood_frame=good_frame;
    if(good_frame)
    {
     frame=this_frame;
     if(frame++=='z') frame='a';
    }

    if(tsover) break;

    if(tsretry<10)
    {
    tsretry=10;
    /* tswrite(13,10-tsretry); */
    } 
    tsnext();
   }
  }
  else
  {                                     /* this frame is trashed */
   tshehe();
   if(tsretry==0) return(1);
  }
 }
 return(0);
}



static char * tserrmess[7]=
{
 "{CET00}" /* "Transfer complete", */
 "{CET01}" /* "Too many retries", */
 "{CET02}" /* "Can't find header", */
 "{CET03}" /* "Lost block synch", */
 "{CET04}" /* "Cancelled", */
 "{CET05}" /* "Filing system error",*/
 "{CET06}" /* "Need Viewdata terminal" */
};



void tsdlx(void)
{
 int i;

 if(vxexists)
 {
  tsfp=NULL;
  i=tsdownload();
  if(tsfp)
  {
   if(i) ftpclosewrite(tsfp,lastframe,FTPCLOSEERROR);
   else  ftpclosewrite(tsfp,"{CET07}",0);   /* transfer complete */
  }
 }
 else i=6;

 ftpinfo(tserrmess[i]);
}


