/***************************************************************************
 *                                                                         *
 *   FTFASCII.C                                                            *
 *                                                                         *
 *   Copyright (c) 1992-1997 Galacticomm, Inc.      All Rights Reserved.   *
 *                                                                         *
 *   File Transfer Software for ASCII protocols                            *
 *                                                                         *
 *   With all operating-system-specific functions removed (I/O, disk,      *
 *   memory, time), the pure file transfer algorithm can be isolated,      *
 *                                                                         *
 *                                               - R. Stein  1/17/92       *
 *                                                                         *
 ***************************************************************************/

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

#define FILREV "$Revision: 4 $"

#define LINLEN 256           /* maximum length of lines transmitted fm file */

#define AXWAIT (2*16)          /* patience waiting for all output to go out */

CHAR *pretarg="[33m";                 /* string to prefix located targets */
CHAR *postarg="[32m";                /* string to postfix located targets */

/*--- ASCII receiver states ---*/
#define ARFILE    1                                   /* receiving the file */
#define ARDONE    2                      /* received EOF, will end transfer */
#define AREND     3                                       /* end of receive */

/*--- ASCII transmitter states ---*/
#define AXFILE    1                               /* open file for transmit */
#define AXSEND    2                                         /* transmitting */
#define AXEOF     3                                          /* end of file */
#define AXEND     4                                  /* end of transmission */


/*--- ASCII receive routines ---*/

static VOID
asrini(VOID)                                   /* Initialize ASCII receiver */
{
}

static VOID
asrsrt(VOID)                                 /* Begin ASCII receive session */
{
     setmem(ftfscb,sizeof(*ftfscb),0);
     if (ftfrop(0,(ftfpsp->flags&FTFASF) != 0,0) != 0) {
          ftfabt(ftfscb->abwhy);
          return;
     }
     ftfsrt();
     ftfnew(ARFILE);
}

static VOID
asrins(                /* Handle incoming line during ASCII receive session */
CHAR *stg)               /* not including line terminator, "OK" will be EOF */
{
     INT n;

     if (stg == NULL) {
          return;
     }
     n=strlen(stg);
     ftfscb->actbyt+=n+2;
     if (sameas(stg,"OK")) {
          ftfnew(ARDONE);
     }
     else if (ftfrwr(stg,n) != n || ftfrwr("\n",1) != 1) {
          ftfabt("Error writing file. (Disk full?)");
     }
     else {
          ftfcbl();
     }
}

static INT
asrctn(VOID)                                      /* Continue ASCII receive */
{
     switch(ftfscb->state) {
     case ARFILE:
          if (ftfpsp->byttmo > 0 && ftftck-ftfscb->tckbyt > ftfpsp->byttmo) {
               ftfous("");
               ftfscb->tckbyt=ftftck;
          }
          break;
     case ARDONE:
          ftfrcl(1);
          ftfscb->isopen=0;
          ftfscb->actfil++;
          ftfnew(AREND);
          break;
     case AREND:
          return(0);
     case FTFABORT:
          ftfrca();
          return(-1);
     }
     return(1);
}


/*--- ASCII transmit routines ---*/

static VOID
asxini(VOID)                                      /* Init ASCII transmitter */
{
}

static VOID
asxsrt(VOID)                                /* Begin ASCII transmit session */
{
     setmem(ftfscb,sizeof(*ftfscb),0);
     ftfnew(AXFILE);
}

static VOID
ftfops(                  /* output only n characters of 0-terminated string */
CHAR *string,                    /* warning, string is temporarily modified */
INT n)
{
     CHAR c;

     c=string[n];
     string[n]='\0';
     ftfous(string);
     string[n]=c;
}

static CHAR *
strstri(                               /* sub-string scan, case insensitive */
CHAR *string,                                                     /* string */
CHAR *sub)                               /* substring to look for in string */
{
     INT i,n;

     for (i=0,n=strlen(string)-strlen(sub) ; i <= n ; i++,string++) {
          if (sameto(sub,string)) {
               return(string);
          }
     }
     return(NULL);
}

static INT
asxctn(VOID)                                     /* continue ASCII transmit */
{                                                          /* return 0=done */
     INT i,n;
     CHAR *cp;
     INT crline;
     INT lines;

     switch (ftfscb->state) {
     case AXFILE:
          if (ftfoba() == ftfomt) {
               if (ftfxop() == 0) {
                    ftfsrt();
                    ftfnew(AXSEND);
               }
               else {
                    ftfnew(AXEND);
               }
          }
          break;
     case AXSEND:
          for (lines=0 ; lines < LCHUNK
            && ftfoba() >= LINLEN+1
            && ftfscb->state == AXSEND ; lines++) {
               if ((n=ftfxrl(ftfbuf,LINLEN+1)) == 0) {
                    ftfnew(AXEOF);
               }
               else if (n > 0) {
                    if ((crline=(ftfbuf[n-1] == '\n')) != 0) {
                         ftfbuf[--n]='\0';
                         depad(ftfbuf);
                    }
                    ftfscb->actbyt+=n+2;
                    if (ascscb->target[0] == '\0'
               || (ascscb->alttrg[0] != '\0'
                   && sameto(ascscb->alttrg,ftfbuf))) {
                         ftfous(ftfbuf);
                    }
                    else if ((cp=strstri(ftfbuf,ascscb->target)) != NULL) {
                         i=(INT)(cp-ftfbuf);
                         n=i+strlen(ascscb->target);
                         ftfops(ftfbuf,i);
                         ftfous(pretarg);
                         ftfops(ftfbuf+i,n-i);
                         ftfous(postarg);
                         ftfous(ftfbuf+n);
                    }
                    else {
                         crline=0;
                    }
                    if (crline) {
                         ftfous("\r");
                    }
               }
               else {
                    ftfabt("File read error.");
               }
               ftfscb->tckact=ftftck;
               ftfact=1;
          }
          break;
     case AXEOF:
          if (ftfoba() == ftfomt) {
               ftfxcl(1);
               ftfscb->isopen=0;
               ftfscb->actfil++;
               ftfnew(AXFILE);
          }
          break;
     case AXEND:
          return(0);
     case FTFABORT:
          ftfxca();
          return(-1);
     }
     return(1);
}

static VOID
asxins(               /* Handle incoming line during ASCII transmit session */
CHAR *stg)
{
     ftfabt(stg == NULL ? "" : "Operator abort");
}

                /* Note: screen-pausing must be handled by operating system */

                   /* Note: for ASCII protocols to receive and transmit     */
                   /* unix style text files, you can clear the FTFASF flag. */

struct ftfpsp ftpasr={                                   /* ASCII receiving */
     NULL,
     "A",                                  /* 1-3 code letters for protocol */
     "ASCII",                                           /* name of protocol */
     FTFASC+FTF7BT+FTFASF+FTFXTD,              /* protocol capability flags */
     sizeof(struct ftfscb),        /* total length of session control block */
     60*16,     /* .byttmo                             default byte timeout */
     0,         /* .paktmo                           default packet timeout */
     0,         /* .retrys                              default max retries */
     0L,        /* .window   max window size (packets/bytes as appropriate) */
     0,         /* .paksiz                        packet size 0=auto-figure */
     asrini,    /* .initze()    Initialize this protocol (recompute scblen) */
     asrsrt,    /* .start()                                Start a transfer */
     asrctn,    /* .contin()              Continuously call, 1=more, 0=done */
     NULL,      /* .hdlinc()                       Handle one incoming byte */
     asrins,    /* .hdlins()                   Handle incoming line of text */
     ftfabt,    /* .term()        Initiate graceful termination of transfer */
     ftfrca,    /* .abort()  Immediately unconditionally abort the transfer */
     NULL,      /* .hdlinb()              Handle an array of incoming bytes */
     "",        /* .secur                App-specific security of some kind */
     {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};

struct ftfpsp ftpasx={                   /* (continuous) ASCII transmitting */
     NULL,
     "A",                                  /* 1-3 code letters for protocol */
     "ASCII (continuous dump)",                         /* name of protocol */
     FTFXMT+FTFASC+FTFMUL+FTF7BT+FTFASF+FTFAFN+FTFXTD,
                                               /* protocol capability flags */
     sizeof(struct ftfscb),        /* total length of session control block */
     0,         /* .byttmo                             default byte timeout */
     0,         /* .paktmo                           default packet timeout */
     0,         /* .retrys                              default max retries */
     0L,        /* .window   max window size (packets/bytes as appropriate) */
     0,         /* .paksiz                        packet size 0=auto-figure */
     asxini,    /* .initze()    Initialize this protocol (recompute scblen) */
     asxsrt,    /* .start()                                Start a transfer */
     asxctn,    /* .contin()              Continuously call, 1=more, 0=done */
     NULL,      /* .hdlinc()                       Handle one incoming byte */
     asxins,    /* .hdlins()                   Handle incoming line of text */
     ftfabt,    /* .term()        Initiate graceful termination of transfer */
     ftfxca,    /* .abort()  Immediately unconditionally abort the transfer */
     NULL,      /* .hdlinb()              Handle an array of incoming bytes */
     "",        /* .secur                App-specific security of some kind */
     {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};

struct ftfpsp ftplsx={                /* (screen-paused) ASCII transmitting */
     NULL,
     "L",                                  /* 1-3 code letters for protocol */
     "Listing (a screen at a time)",                    /* name of protocol */
     FTFXMT+FTFASC+FTFMUL+FTF7BT+FTFASF+FTFAFN+FTFXTD,
                                               /* protocol capability flags */
     sizeof(struct ftfscb),        /* total length of session control block */
     0,         /* .byttmo                             default byte timeout */
     0,         /* .paktmo                           default packet timeout */
     0,         /* .retrys                              default max retries */
     0L,        /* .window   max window size (packets/bytes as appropriate) */
     0,         /* .paksiz                        packet size 0=auto-figure */
     asxini,    /* .initze()    Initialize this protocol (recompute scblen) */
     asxsrt,    /* .start()                                Start a transfer */
     asxctn,    /* .contin()              Continuously call, 1=more, 0=done */
     NULL,      /* .hdlinc()                       Handle one incoming byte */
     asxins,    /* .hdlins()                   Handle incoming line of text */
     ftfabt,    /* .term()        Initiate graceful termination of transfer */
     ftfxca,    /* .abort()  Immediately unconditionally abort the transfer */
     NULL,      /* .hdlinb()              Handle an array of incoming bytes */
     "",        /* .secur                App-specific security of some kind */
     {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};

