/***************************************************************************
 *                                                                         *
 *   FTF.C                                                                 *
 *                                                                         *
 *   Copyright (c) 1991-1997 Galacticomm, Inc.      All Rights Reserved.   *
 *                                                                         *
 *   File Transfer Software - whatever's common to more than one protocol  *
 *                                                                         *
 *   With all operating-system-specific functions removed (I/O, disk,      *
 *   memory, time), the pure file transfer algorithm can be isolated,      *
 *                                                                         *
 *                                             - R. Stein  5/19/91         *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "ftf.h"

#define FILREV "$Revision: 4 $"

struct ftfpsp
  *ftfpsp,                       /* global input to all entry/exit routines */
  *fthead=NULL,                           /* addr of 1st entry in prot list */
  *fttail=(struct ftfpsp *)(&fthead);    /* addr of last entry in prot list */

struct ftfscb *ftfscb;   /* global input to all entry/exit routines, except */
                                                                /* initze() */

INT scbmax=(sizeof(struct ftfscb));                  /* size of biggest scb */

CHAR *ftfbuf;                         /* temporary (very short-term) buffer */
INT fbleng;                                   /* length of temporary buffer */
CHAR ftfact;                    /* 1=cycle produced some action 0=quiescent */
     /* protocols should set whenever some progress is made in the transfer */
/* application may wish to handle consistent (ftfact == 0)'s in some manner */

static CHAR cli;                           /* between ftfinb() and ftfcib() */

static VOID
ftplogged(                            /* protocol is in list, initialize it */
struct ftfpsp *ftp)                             /* put it BEFORE all others */
{
     if (ftp->initze != NULL) {
          ftp->initze();
     }
     if (ftp->scblen > scbmax) {
          scbmax=ftp->scblen;
     }
}

VOID
ftplog(                              /* log in a new protocol specification */
struct ftfpsp *ftp)                              /* put it after all others */
{
     ftp->next=NULL;
     fttail->next=ftp;
     fttail=ftp;
     ftplogged(ftp);
}

VOID
ftplogh(                             /* log in a new protocol specification */
struct ftfpsp *ftp)                             /* put it BEFORE all others */
{
     ftp->next=fthead;
     fthead=ftp;
     if (fttail == (struct ftfpsp *)(&fthead)) {
          fttail=ftp;
     }
     ftplogged(ftp);
}

VOID
ftfnew(            /* transition to a new sub-state of the transfer session */
INT nstate)
{
     ftfscb->state=nstate;
     ftfscb->tckstt=ftftck;
     ftfscb->tckbyt=ftftck;
}

VOID
ftfahd(                    /* transit to a new sub-state & quickly time out */
INT nstate,
INT ticks)                                /* set times BEHIND by this much! */
{
     ftfscb->state=nstate;
     ftfscb->tckstt=ftftck-ticks-1;
     ftfscb->tckbyt=ftftck-ticks-1;
}

VOID
ftfstf(VOID)                            /* start file counters from scratch */
{      /* called after open successful & perhaps again when transfer starts */
     ftfscb->actbyt=0L;
     ftfscb->actpak=0L;
     ftfscb->acttck=1L;
     ftfscb->garbag=0L;
     ftfscb->tmouts=0L;
     ftfscb->retrys=0L;
     ftfscb->tckfil=ftftck;
     ftfscb->tckbyt=ftftck;
     ftfscb->tckact=ftftck;
}

VOID
ftfsrt(VOID)                           /* start a(nother) transmitable file */
{
     ftfscb->isopen=1;
     ftfscb->tryfil++;
     ftfstf();
}

VOID
ftfnwp(VOID)                                /* new packet received or ACK'd */
{
     UINT n;

     ftfscb->actpak++;
     n=ftftck-ftfscb->tckfil;
     ftfscb->tckfil+=n;
     ftfscb->acttck+=n;
}

VOID
ftfabt(                                           /* abort transfer session */
CHAR *why)                               /* explanation (complete sentence) */
{
     ftfscb->abwhy=why;
     ftfnew(FTFABORT);
}

VOID
ftfcan(VOID)          /* Cancel file transfer, send ^X's to the other party */
{
     static CHAR canistr[]={24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8};

     ftfout(canistr,sizeof(canistr));
}

VOID
ftfrca(VOID)               /* Abort, and possibly abandon a receive session */
{
     ftfclo();
     ftfcli();
     if (ftfscb->isopen) {
          ftfrcl(0);
          ftfscb->isopen=0;
     }
}

VOID
ftfxca(VOID)              /* Abort, and possibly abandon a transmit session */
{
     ftfclo();
     ftfcli();
     if (ftfscb->isopen) {
          ftfxcl(0);
          ftfscb->isopen=0;
     }
}

INT
ftfcbl(VOID)            /* check byte-limit during receive, 1=ok, 0=aborted */
{
     if (ftfscb->actbyt > ftfscb->maxbyt) {
          ftfabt("Ran out of room for this file.");
          return(0);
     }
     return(1);
}

VOID
ftfinc(                  /* does protocol's hdlinc() work by using hdlinb() */
CHAR c)                             /* This is a handy hdlinc() entry point */
{                       /* for new protocols to work with old applications. */
     ftfpsp->hdlinb(&c,1);
}

SHORT
ftfinbc(                 /* does protocol's hdlinb() work by using hdlinc() */
CHAR *bytes,                        /* This is a handy hdlinb() entry point */
UINT nbytes)           /* for old protocol code to use the FTFXTD structure */
       /* (warning! an ftfpsp should never use BOTH ftfinc() and ftfinbc()) */
{
     VOID (*hicptr)(CHAR);

     hicptr=ftfpsp->hdlinc;
     for (cli=0 ; nbytes > 0 && !cli ; nbytes--) {
          (*hicptr)(*bytes++);
     }
     return(nbytes);
}

INT
ftfinb(          /* for application to handle a block of binary input bytes */
CHAR *bytes,  /* (allows new applications to work with old & new protocols) */
UINT nbytes)                                         /* (see also ftfcib()) */
{
     if (ftfpsp->flags&FTFXTD) {
          return(ftfpsp->hdlinb(bytes,nbytes));
     }
     else {
          return(ftfinbc(bytes,nbytes));
     }
}

VOID
ftfcib(VOID)       /* application clear input bytes coming in thru ftfinb() */
                                      /* If your application uses ftfinb(), */
{                               /* then your ftfcli() should call ftfcib(). */
     cli=1;
}
