/*
 * zmodem.c
 *
 *  Created on: Sep 3, 2024
 *      Author: tm
 */

#include "config.h"
#include "system.h"
#include "zmodem.h"
#include "user_io.h"
#include "microsd.h"
#include "uartstdio.h"  // User local version with larger RX buffer

extern FIL FileObject;      //defd in main.c (was ymodem.c)


//#ifdef NOZMODEM



// -------------- cf2_zmod.c
/************************************************************************/
/* Copyright 2013 MBARI                         */
/************************************************************************/
/* Summary  : Platform-specific routines for porting Embedded ZModem to BEDS*/
/* Filename : bedszm.c                          */
/* Author   : Robert Herlien (rah)                  */
/* Project  : Benthic Event Detection System (BEDS)         */
/* Revision : 1.0                           */
/* Created  : 10/2/2013                         */
/*                                      */
/* MBARI provides this documentation and code "as is", with no warranty,    */
/* express or implied, of its quality or consistency. It is provided without*/
/* support and without obligation on the part of the Monterey Bay Aquarium  */
/* Research Institute to assist in its use, correction, modification, or    */
/* enhancement. This information should not be published or distributed to  */
/* third parties without specific written permission from MBARI.            */
/*                                      */
/************************************************************************/
/* Modification History:                        */
/* 2oct2013 rah - created                       */
// 9/30/2014 LJCOLETTI - modified for use with MSC (MBARI SENSOR CONTROLLER)
/************************************************************************/
/* The following copyright is included because some routines were taken */
/* from Omen's rbunix.c.  Note that MBARI has licensed Industrial ZModem*/
/* from Omen Technology.                        */
/*
 *  This file contains Linux/Unix specific code for setting terminal modes,
 *  very little is specific to ZMODEM per se
 *  Copyright 2011 Omen Technology INC All Rights Reserved
 */
/************************************************************************/

//#include <cfxpico.h>        /* Persistor PicoDOS definitions    */

//#undef TRUE   //APFTODO
//#undef FALSE

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
//#include <unistd.h>
//#include <sys/stat.h>
#include <string.h>
//#include <dirent.h>
#include <time.h>


#include "stdint.h"
#include "system.h"


#include "user_io.h"
#include "microsd.h"
#include "uartstdio.h"  // User local version with larger RX buffer
#include "zmodem.h"     //"izm.h"









/****************************************/
/*  External Data           */
/****************************************/

extern int  Verbose, errcnt, blklen, Eofseen;
extern char *secbuf;
extern unsigned Txwindow, Tframlen;
extern char Lzconv;

#ifdef NOCOPYTX
extern char privsecbuf[];
#endif


/****************************************/
/*  Module Local Data       */
/****************************************/

#define OK      0
#define ERROR   -1

#define NumberOf(arr)       ((sizeof(arr) / sizeof(arr[0])))

static FILE *infp = NULL;
//static struct stat filestat;  // APFTODO "../zmodem.c", line 94: error #237: variable "filestat" was declared with a never-completed type
static const char *logNames[] = {"SYS.LOG", "MPU.LOG", "SZ.LOG"};

typedef enum {LOG_MSC=0, LOG_MPU, LOG_ZMODEM} SysLogType;

//APFTODO -
//"../zmodem.c", line 333: error #148: declaration is incompatible with "int dirScan(char *, char *, int (*)(char *, struct dirent *, void *), void *)" (declared at line 99)
//int         dirScan(char *pathStr, char *matchStr, int (*func)(char *path, struct dirent *, void *), void *parm);
long int    vSysLogPrintf(int ltype, const char *fmt, va_list vlist);
long        sysLogPrintf(const char *fmt, ...);

/************************************************************************/
/* Function    : sendline                       */
/* Purpose     : Contrary to the name, send one CHARACTER to the serial port*/
/* Inputs      : Character to send                  */
/* Outputs     : None                           */
/************************************************************************/
void sendline(int c)
{
#ifdef APFTODO
    SCITxPutChar((ushort)(c & 0xff));
#endif
}

/************************************************************************/
/* Function    : readline                       */
/* Purpose     : Read one CHARCTER from the host            */
/* Inputs      : Timeout, in tenths of a second             */
/* Outputs     : None                           */
/************************************************************************/
int readline(int timeout)
{
    short tmout, chr;
    int   remaining;
#define TMOUT_MAX   327

    for (remaining = timeout; remaining > 0; remaining -= tmout)
    {
    tmout = (remaining > TMOUT_MAX ? TMOUT_MAX : remaining);
    chr = SCIRxGetCharWithTimeout((short)(100*tmout));
    if (chr != -1)
        return(chr & 0xff);
    }
    return(TIMEOUT);

}

/************************************************************************/
/* Function    : checkline                      */
/* Purpose     : Determine if there are characters available        */
/* Inputs      : None                           */
/* Outputs     : Non-zero if chars available, else zero         */
/************************************************************************/
int checkline(void)
{
    return(SCIRxQueuedCount());
}

void purgeline(void)
{
    SCIRxFlush();
}

void flushmo(void)
{
    SCITxWaitCompletion();
}

/************************************************************************/
/* Function    : vfile                          */
/* Purpose     : Log an error                       */
/* Inputs      : format string, 4 parameters                */
/* Outputs     : None                           */
/************************************************************************/
void vfile(char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    if (Verbose > 2) {
    vSysLogPrintf(LOG_ZMODEM, fmt, ap);
    }
}

/************************************************************************/
/* Function    : zperr                          */
/* Purpose     : Log an error                       */
/* Inputs      : format string, 2 parameters                */
/* Outputs     : None                           */
/************************************************************************/
void zperr(char *s, ...)
{
    va_list ap;

    va_start(ap, s);
    if (Verbose > 0) {
    vSysLogPrintf(LOG_ZMODEM, s, ap);
    }
}

/************************************************************************/
/* Function    : insertStat                     */
/* Purpose     : Insert file status information into buffer     */
/* Inputs      : char ptr                       */
/* Outputs     : Length of inserted string              */
/************************************************************************/
int insertStat(char *q)
{
    //sprintf(q, "%lu %lo", filestat.st_size, filestat.st_mtime);
    //sprintf(q, "%lu %lu", filestat.st_size, filestat.st_mtime);    //APFTODO "../zmodem.c", line 195: error #71: incomplete type is not allowed

    return(strlen(q));
}

/************************************************************************/
/* Function    : zseek                          */
/* Purpose     : Seek to given position in nput file            */
/* Inputs      : File position                      */
/* Outputs     : Current file offset, or -1 if function failed      */
/************************************************************************/
int zseek(long n)
{
    clearerr(infp);             /* Clear EOF */
    //return(fseek(infp, n, SEEK_SET));
    return(f_lseek(infp, n));
}

/************************************************************************/
/* Function    : zfilbuf                        */
/* Purpose     : Fill buffer with blklen chars              */
/* Inputs      : None                           */
/* Outputs     : Number characters read                 */
/************************************************************************/
int zfilbuf(void)
{
    size_t n;

#ifdef NOCOPYTX
    n = fread(secbuf=privsecbuf, 1, blklen, infp);
#else
    n = fread(secbuf, 1, blklen, infp);
#endif
    if (n < blklen)
    Eofseen = 1;
    return(n);
}

/************************************************************************/
/* Function    : zclose                         */
/* Purpose     : Close the input file                   */
/* Inputs      : status                         */
/* Outputs     : None                           */
/************************************************************************/
void zclose(int status)
{
#ifdef DIAGS
    vfile("zclose: status=%d", status);
#endif
    if (infp != NULL) {
    f_close(infp);
    } else {
#ifdef DIAGS
    vfile("file already closed!!");
#endif
    }

    infp = NULL;
}

/****************************************************************/
/* Functions to support calling ZModem from BEDS code       */
/****************************************************************/

int zmodem_send(int argc, char *argv[])
{
    uint32_t    file_size;
    FRESULT     fresult;
    char        filename[30];
    int         error;

    UARTEchoSet(false);     // Disable console echo

    strncpy(filename, argv[1], sizeof(filename));
    printf("\n\nfilename = %s\n", filename);

    // Open the file for reading.
    fresult = f_open(&FileObject, filename, FA_READ);
    if(fresult != FR_OK)
    {
        printf("f_open error: %s\n", StringFromFresult(fresult) );
        error = -1;
        goto abort;
    }

    file_size = f_size(&FileObject);  // Set file size
    printf("File size = %lu\n", file_size);

    uprintf("Zmodem sending %s, %lu bytes...\r\n", filename, file_size);    //uprintf("Ymodem sending %s...\r\n", filename);
    UARTFlushTx(false);

abort:
    prn_nl(); uprintf("Zmodem aborted"); prn_nl();
    MAP_SysCtlDelay(MILLISECOND*1000);

success:
    f_close(&FileObject);
    UARTEchoSet(true);      // Enable console echo
}




/************************************************************************/
/* Function    : dsZSend                        */
/* Purpose     : Func sent to dirScan to send file via ZModem       */
/* Inputs      : dirent ptr (per dirScan)               */
/* Outputs     : TRUE to continue, FALSE to stop            */
/************************************************************************/
static int dsZSend(char *path, struct dirent *de)
{
    int  rtn;
    char name[128];

    //snprintf(name, sizeof(name), "%s\\%s", path, de->d_name);  // APFTODO "../zmodem.c", line 269: error #395: pointer to incomplete class type is not allowed

#ifdef APFTODO
    if ((de->d_attr & (_A_SUBDIR | _A_VOLID)) == 0)
    {
        if ((infp=f_open(name, "r"))==NULL)
        {
            ++errcnt;
            return(TRUE);   /* pass over it, there may be others */
        }
    }

    stat(name, &filestat);  /* Get file size, see insertStat()  */
#endif
    rtn = wcs(name);        /* Send one file        */

    sysLogPrintf("%s sent via ZModem, result = %d\n", name, rtn);

    return(rtn == IZOK);    /* If failed protocol, stop */

} /*dsZSend() */


#ifdef CODEFROMINTERNET
https://www.atnf.csiro.au/computing/software/gipsy/sub/filestat.c
fint    filestat_c( fchar   filename ,
                    fint    *atime ,
                    fint    *mtime ,
                    fint    *ftype )
{
   char     *path;
   fint     r = 0;
   struct stat  buf;

   path = zadd( filename );
   r = stat( path, &buf );
   if (!r) {
      (*atime) = (fint) buf.st_atime;
      (*mtime) = (fint) buf.st_mtime;
      if ((buf.st_mode & S_IFMT) == S_IFREG) {
         (*ftype) = 1;
      } else if ((buf.st_mode & S_IFMT) == S_IFDIR) {
         (*ftype) = 2;
      } else {
         (*ftype) = 0;
      }
   free( path );
   }
   return( r );
}
#endif

/************************************************************************/
/* Function    : zmSendFiles                        */
/* Purpose     : Send multiple files via ZModem prototcol       */
/* Inputs      : Name (wildcards supported), verbosity, window size, frame length*/
/* Outputs     : OK or ERROR                        */
/* Comment     : For default, set verbose=0, window=0           */
/************************************************************************/
int zmSendFiles(char *path, char *name, int verbose, unsigned window, unsigned framelen)
{
    Verbose = verbose;
    Txwindow = window;
    Tframlen = framelen;
    Lzconv = ZCRESUM;         /* Ask receiver for crash recovery */
    errcnt = 0;

    sysLogPrintf("Starting ZModem send for %s %s\n", path, name);

    RTCDelayMicroSeconds(500000);

    startz();
    dirScan(path, name, dsZSend, NULL);
    saybibi();

    SCITxFlush();
    sysLogPrintf("ZModem finished, errcnt = %d\n", errcnt);

    return(errcnt == 0 ? OK : ERROR);
}

/************************************************************************/
/* Function    : dirScan                        */
/* Purpose     : Execute function for every directory entry matching pattern*/
/* Inputs      : Wildcard pattern to match, function ptr, function parm */
/* Outputs     : None                           */
/************************************************************************/
//int dirScan(char *,        char *,         int (*)(char *,         struct dirent *, void *), void *)"

int dirScan(char *pathStr, char *matchStr, int (*func)(char *path, struct dirent *, void *), void *parm)
{
    //"../zmodem.c", line 339: error #71: incomplete type is not allowed
    int     rtn = TRUE;
#ifdef APFTODO
    struct dirent   de;
    int     rtn = TRUE;

    if (pathStr == NULL)
        pathStr = "C:";

    if (matchStr == NULL)
        matchStr = "*.LOG";

    if (DIRFindFirst(pathStr, &de) != dsdEndOfDir)
    {
    do
    {
        if (DIRMatchName((char *) de.d_name, matchStr))
        if ((rtn = (*func)(pathStr, &de, parm)) == FALSE)
            break;
    } while (DIRFindNext(&de) != dsdEndOfDir);
    }

    DIRFindEnd(&de);
#endif
    return(rtn);

} /* dirScan() */

/************************************************************************/
/* Function    : vSysLogPrintf                      */
/* Purpose     : Write an entry into the system log file, vprintf style */
/* Inputs      : Format, va_list                    */
/* Outputs     : Number of chars printed                */
/************************************************************************/
long vSysLogPrintf(int ltype, const char *fmt, va_list vlist)
{
    FIL    *logfp;
    time_t  now;
    long    rtn;
    struct tm   *tmp;
    FRESULT fres;

    if (ltype >= NumberOf(logNames))
        return(0);

    fres = f_open(logfp, logNames[ltype], "a+");
    if(fres ==  NULL)
        return(0);


#ifdef OLDCODE
    if ((ltype >= NumberOf(logNames)) ||
    ((logfp = f_open(logNames[ltype], "a+")) == NULL))
    return(0);
#endif

    now = RTCGetTime( NULL, NULL );
    tmp = gmtime(&now);

    rtn = f_printf(logfp, "%04d/%02d/%02d %02d:%02d:%02d, ",
          tmp->tm_year+1900, tmp->tm_mon+1, tmp->tm_mday,
          tmp->tm_hour, tmp->tm_min, tmp->tm_sec);

    rtn += vf_printf(logfp, fmt, vlist);
    if (fmt[strlen(fmt)-1] != '\n')
    rtn += f_printf(logfp, "\r\n");
    f_close(logfp);

    return(rtn);

} /* vSysLogPrintf() */

/************************************************************************/
/* Function    : sysLogPrintf                       */
/* Purpose     : Write an entry into the system log file, printf style  */
/* Inputs      : String to write, arguments             */
/* Outputs     : Number of chars printed                */
/************************************************************************/
long sysLogPrintf(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    return(vSysLogPrintf(LOG_MSC, fmt, ap));

} /* sysLogPrintf() */






// -------------- icrctab.c
/*
 *  Crc calculation stuff
 */

/* crctab calculated by Mark G. Mendel, Network Systems Corporation */
static unsigned short icrctab[256] = {
    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
};

/*
 * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
 *  NOTE: First srgument must be in range 0 to 255.
 *        Second argument is referenced twice.
 *
 * Programmers may incorporate any or all code into their programs,
 * giving proper credit within the source. Publication of the
 * source routines is permitted so long as proper credit is given
 * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
 * Omen Technology.
 */

#define updcrc(cp, crc) ( icrctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)

/*
 * Copyright (C) 1986 Gary S. Brown.  You may use this program, or
 * code or tables extracted from it, as desired without restriction.
 */

/* First, the polynomial itself and its table of feedback terms.  The  */
/* polynomial is                                                       */
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
/* Note that we take it "backwards" and put the highest-order term in  */
/* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */
/* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */
/* the MSB being 1.                                                    */

/* Note that the usual hardware shift register implementation, which   */
/* is what we're using (we're merely optimizing it by doing eight-bit  */
/* chunks at a time) shifts bits into the lowest-order term.  In our   */
/* implementation, that means shifting towards the right.  Why do we   */
/* do it this way?  Because the calculated CRC must be transmitted in  */
/* order from highest-order term to lowest-order term.  UARTs transmit */
/* characters in order from LSB to MSB.  By storing the CRC this way,  */
/* we hand it to the UART in the order low-byte to high-byte; the UART */
/* sends each low-bit to hight-bit; and the result is transmission bit */
/* by bit from highest- to lowest-order term without requiring any bit */
/* shuffling on our part.  Reception works similarly.                  */

/* The feedback terms table consists of 256, 32-bit entries.  Notes:   */
/*                                                                     */
/*     The table can be generated at runtime if desired; code to do so */
/*     is shown later.  It might not be obvious, but the feedback      */
/*     terms simply represent the results of eight shift/xor opera-    */
/*     tions for all combinations of data and CRC register values.     */
/*                                                                     */
/*     The values must be right-shifted by eight bits by the "updcrc"  */
/*     logic; the shift must be unsigned (bring in zeroes).  On some   */
/*     hardware you could probably optimize the shift in assembler by  */
/*     using byte-swap instructions.                                   */

static unsigned long icr3tab[] = { /* CRC polynomial 0xedb88320 */
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};

#ifdef NFGM
unsigned long
UPDC32(b, c)
long c;
{
    return (icr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF));
}

#else

#define UPDC32(b, c) (icr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF))
#endif


/* End of icrctab.c */




// -------------- irz.c

/*% cc -g -DUNIX -DDIAGS -MAXTRIES=100 -DRXTIMEOUT=2  % -o irz; size irz;
 *
 * irz.c By Chuck Forsberg
 *  Copyright 2005 2011 Omen Technology INC All Rights Reserved
 *     This is UNPUBLISHED PROPRIETARY SOURCE CODE of Omen Technology INC.
 *     The Copyright notice above does not evidence any actual or intended
 *     publication such source code.
 *
 *  Entry:
 *  int rz();
 *      returns IZOK or IZERROR
 *
 *  External functions called:
 *
 * sendline(c)  sends a character to host
 * purgeline()  empty receive queue
 * int readline(tenths) read char from host, timeout in seconds/10
    return received byte 0 to 0377
    negative return values indicate error:
        return -1 on recoverable error
        return -2 on timeout
    trap fatal errors (loss of carrier, etc.), close file
 * sendbrk() send a break signal (not likely to be needed)
 *
 * long crprocheader(s) parse filename, decide what to do with
 *  if (zconv==ZCRESUM) means sender requests crash recovery
 * incoming file:
 *  return ERROR to skip
 *  opens it for writing
 *  Returns restart address if crash recovery desired, else 0
 *
 * putsec(s, n) write n bytes, trap errors
 *  Writing assumed to begin at the address returned by crprocheader()
 * closeit(status) finish writing
 *  trap on error
 *  N.B: closeit might be called after the file is closed.
 * When trapping on errors, close file, call canit() unless line dropped
 */

int tryz(), rz(), rzfiles(), rzfile();
long crprocheader();
void closeit(int), putsec(), sendbrk();

#ifndef XEDSINIT
void zmputs();
#endif

#ifndef BOTH

#ifndef IZOK
#include "izm.h"
#endif

// COLETTI moved here for compiler
int Verbose=0;


//#include "icrctab.c"
//to keep compiler from complaining I inserted icrctab.c instead of "including" it

#ifdef DUPCODE
/*
 *  Crc calculation stuff
 */

/* crctab calculated by Mark G. Mendel, Network Systems Corporation */
static unsigned short icrctab[256] = {
    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
};

#endif

/*
 * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
 *  NOTE: First srgument must be in range 0 to 255.
 *        Second argument is referenced twice.
 *
 * Programmers may incorporate any or all code into their programs,
 * giving proper credit within the source. Publication of the
 * source routines is permitted so long as proper credit is given
 * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
 * Omen Technology.
 */

#define updcrc(cp, crc) ( icrctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)

/*
 * Copyright (C) 1986 Gary S. Brown.  You may use this program, or
 * code or tables extracted from it, as desired without restriction.
 */

/* First, the polynomial itself and its table of feedback terms.  The  */
/* polynomial is                                                       */
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
/* Note that we take it "backwards" and put the highest-order term in  */
/* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */
/* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */
/* the MSB being 1.                                                    */

/* Note that the usual hardware shift register implementation, which   */
/* is what we're using (we're merely optimizing it by doing eight-bit  */
/* chunks at a time) shifts bits into the lowest-order term.  In our   */
/* implementation, that means shifting towards the right.  Why do we   */
/* do it this way?  Because the calculated CRC must be transmitted in  */
/* order from highest-order term to lowest-order term.  UARTs transmit */
/* characters in order from LSB to MSB.  By storing the CRC this way,  */
/* we hand it to the UART in the order low-byte to high-byte; the UART */
/* sends each low-bit to hight-bit; and the result is transmission bit */
/* by bit from highest- to lowest-order term without requiring any bit */
/* shuffling on our part.  Reception works similarly.                  */

/* The feedback terms table consists of 256, 32-bit entries.  Notes:   */
/*                                                                     */
/*     The table can be generated at runtime if desired; code to do so */
/*     is shown later.  It might not be obvious, but the feedback      */
/*     terms simply represent the results of eight shift/xor opera-    */
/*     tions for all combinations of data and CRC register values.     */
/*                                                                     */
/*     The values must be right-shifted by eight bits by the "updcrc"  */
/*     logic; the shift must be unsigned (bring in zeroes).  On some   */
/*     hardware you could probably optimize the shift in assembler by  */
/*     using byte-swap instructions.                                   */

#ifdef DUPCODE

static unsigned long icr3tab[] = { /* CRC polynomial 0xedb88320 */
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};

#endif

#ifdef NFGM
unsigned long
UPDC32(b, c)
long c;
{
    return (icr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF));
}

#else

#define UPDC32(b, c) (icr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF))
#endif


/* End of icrctab.c */



#ifndef RXTIMEOUT
#define RXTIMEOUT 100
#endif
int Rxtimeout = RXTIMEOUT;

int Zrwindow = 1400;    /* RX window size (controls garbage count) */

#endif  /* BOTH */

char zconv;     /* ZMODEM file conversion request */


#ifdef UNIX
#define LOGFILE "/tmp/rzlog"
int Verbose=0;
#include "rbunix.c" /* most of the system dependent stuff here */
#endif

#ifndef XEDSINIT
unsigned char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */
#endif

int Zctlesc;        /* Encode control characters */
int tryzhdrtype=ZRINIT; /* Header type to send corresponding to Last rx close */

#ifndef BOTH
//#include "izm.c"
#ifdef ADDRLE
//#include "izmr.c"
#endif
#endif



#ifdef UNIX

/* called by signal interrupt or terminate to clean things up */
void bibi(n)
{
    canit(); mode(0);
    f_printf(stderr, "rz: caught signal %d; exiting", n);
    exit(128+n);
}
usage()
{
    f_printf(stderr, "Usage: irz (NO arguments)\n");
    exit(-1);
}


main(argc, argv)
char *argv[];
{

    char *p;

    if (argc != 1)
        usage();
    if ((p = getenv("VERBOSE")))
        Verbose = atoi(p);

    setbuf(stderr, NULL);
    if (Verbose) {
        if (freopen(LOGFILE, "w", stderr)==NULL) {
            printf("Can't open log file %s\n",LOGFILE);
            exit(0200);
        }
        setbuf(stderr, NULL);
    }
    mode(1);
    if (signal(SIGINT, bibi) == SIG_IGN) {
        signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
    }
    else {
        signal(SIGINT, bibi); signal(SIGKILL, bibi);
    }
    signal(SIGTERM, bibi);
    rz();
    mode(0);
}

#endif

/*
 * Let's receive something already.
 */
int
rz()
{
    register c;

#ifdef BOTH
    Rxtimeout = 100;
#endif
    c=tryz();
    if (c) {
        if (c == ZCOMPL)
            return IZOK;
        if (c == IZERROR)
            goto fubar;
        c = rzfiles();
        if (c)
            goto fubar;
    }
    return IZOK;
fubar:
    canit();
    return IZERROR;
}

/*
 * Initialize for Zmodem receive attempt, try to activate Zmodem sender
 *  Handles ZSINIT frame
 *  Return ZFILE if Zmodem filename received, -1 on error,
 *   ZCOMPL if transaction finished,  else 0
 */
tryz()
{
    register c, n;
#ifdef LDP
    unsigned long crc;
    char *p;
#endif

    for (n=15; --n>=0; ) {
        /* Set buffer length (0) and capability flags */
        stohdr(0L);
#ifdef LDP
        Txhdr[ZF1] = CANLDP;
        /*  Overlays LSB of buffer length!! */
        Txhdr[ZF2] = Zfileclosedok ? 1:0;   /* last file was received and closed ok */
#endif
        Txhdr[ZF0] =
#ifdef ADDRLE
        CANRLE |
#endif
            CANFC32|CANFDX|CANOVIO|CANBRK;
        if (Zctlesc)
            Txhdr[ZF0] |= TESCCTL;
        zshhdr(tryzhdrtype, Txhdr);
        if (tryzhdrtype == ZSKIP)   /* Don't skip too far */
            tryzhdrtype = ZRINIT;   /* CAF 8-21-87 */
again:
        switch (zgethdr()) {
        case ZRQINIT:
            continue;
        case ZEOF:
            continue;
        case TIMEOUT:
            continue;
        case ZFILE:
#ifdef LDP
            bytcnt = 0;
            Zldpactive = Rxhdr[ZF3] & ZSLDP;
            Zcrcpreset = crc = 0xFFFFFFFFL;
#endif
            zconv = Rxhdr[ZF0];
            tryzhdrtype = ZRINIT;
            c = zrdata(secbuf, 1024);
#ifdef UNIX
            mode(3);
#endif
            if (c == GOTCRCW) {
#ifdef LDP
                if (Zldpactive) {
                    for (p=secbuf, c=Rxcount; --c >=0; ++p) {
                        crc = UPDC32(*p, crc);
#ifdef DIAGS
                        vfile("crc=%lX", crc);
#endif
                    }
                    for (p = zcpyrldp; *p; ++p)
                        crc = UPDC32(*p, crc);
                    Zcrcpreset = crc;
#ifdef DIAGS
                    vfile("Zcrcpreset=%lX", Zcrcpreset);
#endif
                }
#endif
                return ZFILE;
            }
            zshhdr(ZNAK, Txhdr);
            goto again;
#ifndef XEDSINIT
        case ZSINIT:
            Zctlesc = TESCCTL & Rxhdr[ZF0];
            if (zrdata((char *)Attn, ZATTNLEN) == GOTCRCW) {
                stohdr(1L);
                zshhdr(ZACK, Txhdr);
                goto again;
            }
            zshhdr(ZNAK, Txhdr);
            goto again;
#endif
        case ZCOMPL:
            goto again;
        default:
            continue;
        case ZFIN:
            zshhdr(ZFIN, Txhdr);
            readline(Rxtimeout);
            readline(Rxtimeout);
            return ZCOMPL;
        case ZCAN:
            return IZERROR;
        }
    }
    return 0;
}

/*
 * Receive 1 or more files with ZMODEM protocol
 */
rzfiles()
{
    register c;

    for (;;) {
        switch (c = rzfile()) {
        case ZEOF:
        case ZSKIP:
        case ZFERR:
            switch (tryz()) {
            case ZCOMPL:
                return IZOK;
            default:
                return IZERROR;
            case ZFILE:
                break;
            }
            continue;
        default:
            return c;
        case IZERROR:
            return IZERROR;
        }
    }
}

#ifndef MAXTRIES
#define MAXTRIES 10
#endif

/*
 * Receive a file with ZMODEM protocol
 *  Assumes file name frame is in secbuf
 */
rzfile()
{
    register c, triesleft;

#ifdef LDP
    Zfileclosedok = 0;  /* last file was received and closed ok */
#endif
    bytcnt = crprocheader(secbuf);
#ifdef DIAGS
    vfile("rzfile: crprocheader returned %ld", bytcnt);
#endif
    if (bytcnt == IZERROR) {
        tryzhdrtype = ZSKIP;
#ifdef DIAGS
        vfile("rzfile: returning ZSKIP");
#endif
        return (ZSKIP);
    }
#ifdef DIAGS
    vfile("rzfile: continuing");
#endif

    triesleft = MAXTRIES;

    for (;;) {
        stohdr(bytcnt);
        zshhdr(ZRPOS, Txhdr);
nxthdr:
        switch (c = zgethdr()) {
        default:
        case ZNAK:
        case TIMEOUT:
            if ( --triesleft < 0) {
#ifdef DIAGS
                vfile("Error count Exceeded");
                vfile("rzfile2: zgethdr returned %d", c);
#endif
                return IZERROR;
            }
            continue;
        case ZFILE: /* ignore duplicate file packet */
            zrdata(secbuf, 1024);
            continue;
        case ZEOF:
            if (rclhdr(Rxhdr) != bytcnt) {
                /*
                 * Ignore eof if it's at wrong place - force
                 *  a timeout because the eof might have gone
                 *  out before we sent our zrpos.
                 */
                goto nxthdr;
            }
            closeit(IZOK);
#ifdef DIAGS
            vfile("rzfile3: normal EOF");
#endif
#ifdef LDP
            Zfileclosedok = 1;  /* last file was received and closed ok */
#endif
            return c;
        case IZERROR:   /* Too much garbage in header search error */
            if ( --triesleft < 0) {
#ifdef DIAGS
                vfile("Error count Exceeded");
                vfile("rzfile4: zgethdr returned %d", c);
#endif
                return IZERROR;
            }
#ifndef XEDSINIT
            zmputs(Attn);
#endif
            continue;
        case ZSKIP:
            closeit(IZERROR);
#ifdef DIAGS
            vfile("rzfile5: Sender SKIPPED file");
#endif
            return c;
        case ZDATA:
            if (rclhdr(Rxhdr) != bytcnt) {
                if ( --triesleft < 0) {
#ifdef DIAGS
                    vfile("Error count Exceeded");
#endif
                    return IZERROR;
                }
    /*  Put these two statements back 7-29-05 CAF */
#ifndef XEDSINIT
                zmputs(Attn);
#endif
                continue;
            }
moredata:
#ifdef UNIX
            if (Verbose>1)
                f_printf(stderr, " %7lX  ", bytcnt);
#endif
            switch (c = zrdata(secbuf, 1024))
            {
            case ZCAN:
#ifdef DIAGS
                vfile("rzfile6: zgethdr returned %d", c);
#endif
                return IZERROR;
            case IZERROR:   /* CRC error */
                if ( --triesleft < 0) {
#ifdef DIAGS
                    vfile("Error count Exceeded");
                    vfile("rzfile7: zgethdr returned %d", c);
#endif
                    return IZERROR;
                }
#ifndef XEDSINIT
                zmputs(Attn);
#endif
                continue;
            case TIMEOUT:
                if ( --triesleft < 0) {
#ifdef DIAGS
                    vfile("Error count Exceeded");
                    vfile("rzfile8: zgethdr returned %d", c);
#endif
                    return IZERROR;
                }
                continue;
            case GOTCRCW:
                triesleft = MAXTRIES;
                putsec(secbuf, Rxcount);
                bytcnt += Rxcount;
                stohdr(bytcnt);
                zshhdr(ZACK, Txhdr);
                sendline(XON);
                goto nxthdr;
            case GOTCRCQ:
                triesleft = MAXTRIES;
                putsec(secbuf, Rxcount);
                bytcnt += Rxcount;
                stohdr(bytcnt);
                zshhdr(ZACK, Txhdr);
                goto moredata;
            case GOTCRCG:
                triesleft = MAXTRIES;
                putsec(secbuf, Rxcount);
                bytcnt += Rxcount;
                goto moredata;
            case GOTCRCE:
                triesleft = MAXTRIES;
                putsec(secbuf, Rxcount);
                bytcnt += Rxcount;
                goto nxthdr;
            }
        }
    }
}

#ifndef XEDSINIT
/*
 * Send a string to the modem, processing for \336 (sleep 1 sec)
 *   and \335 (break signal)
 */
void
zmputs(s)
unsigned char *s;
{
    unsigned char c;

    while (*s) {
        switch (c = *s++) {
        case 0336:
#ifdef FLUSH
            flushmo();
#endif
            while (readline(1) > 0)
                ;
            continue;
        case 0335:
#ifdef FLUSH
            flushmo();
#endif
            sendbrk(); continue;
        default:
            sendline(c);
        }
    }
#ifdef FLUSH
    flushmo();
#endif
}
#endif

#ifdef UNIX

/*
 * Process incoming file information header
 *  Attempts crash recovery if sender asks for it
 *  Returns 0 or file length for success, else IZERROR
 *
 */
long
crprocheader(name)
char *name;
{
    register char *p;
    long mfsize;        /* Size of incoming file */
    struct stat f;

    /* set default parameters and overrides */
    f.st_size = 0;


    if (!name || !*name)
        return IZERROR;
    strcpy(Pathname, name);
    p = name + 1 + strlen(name);
    if (*p) {           /* Y/ZMODEM file info present */
        sscanf(p, "%ld%lo", &mfsize, &Modtime);
        if (Verbose) {
            f_printf(stderr,  "Incoming header: %s\n", p);
            f_printf(stderr,  "Incoming: %s %ld\n", name, mfsize);
        }
    }

    if ((zconv==ZCRESUM) && (stat(name, &f)!= -1)) {
        vfile("Current %s is %ld", name, f.st_size);
        f.st_size &= ~511;
        fout = f_open(name, "r+");
        if ( !fout)
            return IZERROR;
        if (f_lseek(fout, f.st_size, 0)) {
            closeit(IZERROR);
            return IZERROR;
        }
        vfile("Crash recovery at %ld", f.st_size);
    } else
        fout = f_open(name, "w");
    if ( !fout)
        return IZERROR;
    return (f.st_size);
}
#endif  /* UNIX */



/* End of irz.c */



// -------------- isz.c
/*% cc -g -DNOCOPYTX -DMANYREGS -DZSTAB -DUNIX -DDIAGS %  -o isz; size isz;
 ****************************************************************************
 *
 * isz.c By Chuck Forsberg,  Omen Technology INC
 *  Copyright 2004 2011 Omen Technology INC All Rights Reserved
 *     This is UNPUBLISHED PROPRIETARY SOURCE CODE of Omen Technology INC.
 *     The Copyright notice above does not evidence any actual or intended
 *     publication such source code.
 *  Entry: see sample main() in code below
 *
 *  External functions called:
 *
 * sendline(c)  sends a character to host
 *
 * purgeline()  empty receive queue
 * int readline(tenths) read char from host, timeout in seconds/10
    return received byte 0 to 0377
    negative return values indicate error:
        return -1 on recoverable error
        return -2 on timeout
    trap fatal errors (loss of carrier, etc.), close file
 * checkline() return non 0 if readline has 1 or more bytes ready
 *
 * zfilbuf() fill buffer with blklen bytes, set Eofseen if EOT, return count
 *  (See #ifdef NOCOPYTX for alternate version)
 * zseek(whence) clear EOF, errors, seek
 * zclose(status) close the input dataset associated with zfilbuf() et al.
 *  N.B: zclose might be called after the file is closed.
 *
 * When trapping on errors, close file, call canit() unless line dropped
 *
 ****************************************************************************
 */

#ifndef IZOK
#include "izm.h"
#endif

#define LOGFILE "/tmp/szlog"
//int Verbose=0;   //APFTODO
int Fullpath=0;

#ifdef NOCOPYTX
#ifdef KKSIZE
char privsecbuf[KKSIZE];
#else
char privsecbuf[1025];
#endif
#endif

int Zmodem=0;       /* ZMODEM protocol requested by receiver */
unsigned Txwindow=0;    /* Control the size of the transmitted window if non-zero */
unsigned Txwspac;   /* Spacing between zcrcq requests */
unsigned Txwcnt;    /* Counter used to space ack requests */
long vpos = 0;      /* Number of bytes read from file */
long Lrxpos;        /* Receiver's last reported offset */
#ifdef ADDRLE
int Lztrans;
#endif

int wctxpn(), wcs(), getnak(), zsendfile(), getzrxinit(), zsendfdata();
int getinsync(), zfilbuf(), zseek(), zfilbuf(), checkline();
void zclose(int);

//#include "icrctab.c"
//to keep compiler from complaining I inserted icrctab.c instead of "including" it

/*
 *  Crc calculation stuff
 */
#ifdef DUPCODE
/* crctab calculated by Mark G. Mendel, Network Systems Corporation */
static unsigned short icrctab[256] = {
    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
};
#endif
/*
 * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
 *  NOTE: First srgument must be in range 0 to 255.
 *        Second argument is referenced twice.
 *
 * Programmers may incorporate any or all code into their programs,
 * giving proper credit within the source. Publication of the
 * source routines is permitted so long as proper credit is given
 * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
 * Omen Technology.
 */

#define updcrc(cp, crc) ( icrctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)

/*
 * Copyright (C) 1986 Gary S. Brown.  You may use this program, or
 * code or tables extracted from it, as desired without restriction.
 */

/* First, the polynomial itself and its table of feedback terms.  The  */
/* polynomial is                                                       */
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
/* Note that we take it "backwards" and put the highest-order term in  */
/* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */
/* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */
/* the MSB being 1.                                                    */

/* Note that the usual hardware shift register implementation, which   */
/* is what we're using (we're merely optimizing it by doing eight-bit  */
/* chunks at a time) shifts bits into the lowest-order term.  In our   */
/* implementation, that means shifting towards the right.  Why do we   */
/* do it this way?  Because the calculated CRC must be transmitted in  */
/* order from highest-order term to lowest-order term.  UARTs transmit */
/* characters in order from LSB to MSB.  By storing the CRC this way,  */
/* we hand it to the UART in the order low-byte to high-byte; the UART */
/* sends each low-bit to hight-bit; and the result is transmission bit */
/* by bit from highest- to lowest-order term without requiring any bit */
/* shuffling on our part.  Reception works similarly.                  */

/* The feedback terms table consists of 256, 32-bit entries.  Notes:   */
/*                                                                     */
/*     The table can be generated at runtime if desired; code to do so */
/*     is shown later.  It might not be obvious, but the feedback      */
/*     terms simply represent the results of eight shift/xor opera-    */
/*     tions for all combinations of data and CRC register values.     */
/*                                                                     */
/*     The values must be right-shifted by eight bits by the "updcrc"  */
/*     logic; the shift must be unsigned (bring in zeroes).  On some   */
/*     hardware you could probably optimize the shift in assembler by  */
/*     using byte-swap instructions.                                   */

#ifdef APFTODO
static unsigned long icr3tab[] = { /* CRC polynomial 0xedb88320 */
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
#endif
#ifdef NFGM
unsigned long
UPDC32(b, c)
long c;
{
    return (icr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF));
}

#else

#define UPDC32(b, c) (icr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF))
#endif


/* End of icrctab.c */

int Lastrx;
char Lzconv;    /* Local ZMODEM file conversion request */
#ifdef KKSIZE
int blklen=KKSIZE;  /* length of transmitted records */
#else
int blklen=1024;    /* length of transmitted records */
#endif
int Eofseen;        /* EOF seen on input set by zfilbuf */
unsigned Rxbuflen = 16384;  /* Receiver's max buffer length */
unsigned Tframlen = 0;  /* Override for tx frame length */
int Rxflags = 0;
long Lastsync;      /* Last offset to which we got a ZRPOS */
int Beenhereb4;     /* How many times we've been ZRPOS'd same place */
int Zctlesc;    /* Encode control characters */
//int Zrwindow = 1400;    /* RX window size (controls garbage count) */
//int Rxtimeout = 600;
void saybibi(), startz();

int Exitcode;
int errcnt=0;       /* number of files unreadable */
#ifdef UNIX
#include "rbunix.c" /* most of the system dependent stuff here */
#endif

//#include "izm.c"
#ifdef ADDRLE       // TM4C123g is little endian
//#include "izmr.c"
#endif


#ifdef UNIX
FILE *in;

/* called by signal interrupt or terminate to clean things up */
void
bibi(n)
{
    canit(); mode(0);
    f_printf(stderr, "sz: caught signal %d; exiting\n", n);
    if (n == SIGQUIT)
        abort();
    if (n == 99)
        f_printf(stderr, "mode(2) in rbsb.c not implemented!!\n");
    exit(128+n);
}

main(argc, argv)
char *argv[];
{
    register char *cp;
    register npats;
    int dm;
    char **patts;

    if (cp = getenv("VERBOSE"))
        Verbose = atoi(cp);

    npats=0;
    if (argc<2)
        usage();
    while (--argc) {
        cp = *++argv;
        if (*cp++ == '-' && *cp) {
            while ( *cp) {
                switch(*cp++) {
                case 'f':
                    ++Fullpath; break;
                case 'l':
                    if (--argc < 1)
                        usage();
                    Tframlen = atol(*++argv);
                    if (Tframlen<32 || Tframlen>1024)
                        usage();
                    break;
                case 'r':
                    Lzconv = ZCRESUM;
                case 'v':
                    ++Verbose; break;
                case 'w':
                    if (--argc < 1)
                        usage();
                    Txwindow = atoi(*++argv);
                    if (Txwindow < 256)
                        Txwindow = 256;
                    Txwindow = (Txwindow/64) * 64;
                    Txwspac = Txwindow/4;
                    if (blklen > Txwspac)
                        blklen = Txwspac;
                    break;
#ifdef ADDRLE
                case 'Z':
                case 'z':
                    Lztrans = ZTRLE;  break;
#endif
                default:
                    usage();
                }
            }
        }
        else if ( !npats && argc>0) {
            if (argv[0][0]) {
                npats=argc;
                patts=argv;
            }
        }
    }
    if (npats < 1)
        usage();
    if (Verbose) {
        if (freopen(LOGFILE, "w", stderr)==NULL) {
            printf("Can't open log file %s\n",LOGFILE);
            exit(0200);
        }
        setbuf(stderr, NULL);
    }

    mode(1);

    signal(SIGKILL, bibi);
    signal(SIGINT, SIG_IGN);
    signal(SIGQUIT, SIG_IGN);
    signal(SIGTERM, bibi);

    startz();

    if (wcsend(npats, patts)==IZERROR) {
        Exitcode=0200;
        canit();
    }
    mode(0);
    dm = ((errcnt != 0) | Exitcode);
#ifdef DIAGS
    vfile("isz finished with transfers dm=%x", dm);
#endif
    if (dm) {
        exit(dm);
    }
    exit(0);
    /*NOTREACHED*/
}

wcsend(argc, argp)
char *argp[];
{
    register n;

    bytcnt = -1;
    for (n=0; n<argc; ++n) {
        if (wcs(argp[n])==IZERROR)
            return IZERROR;
    }
    saybibi();
    return IZOK;
}
#endif /* UNIX */


#ifdef SAMPLE
main()
{
    startz();       /* Initialize receiver */

    /*
     *  To ask receiver for crash rocovery, set
     *      Lzconv = ZCRESUM;
     *
     * call wcs() once for each file.
     *  Initialize zfilbuf before calling wcs()
     *  The string is the file name, null terminated
     *    file length is not sent
     */
    if (wcs("file.ext"))
        return 1;

    saybibi();      /* Orderly conclusion of ZMODEM session */

    return 0;

}
#endif



void
startz()
{
#ifdef BOTH
    Rxtimeout = 600;
#endif
    Zmodem = 0;
#ifdef LDP
    Zldpactive = 0;
    Zcrcpreset = 0xFFFFFFFFL;   /* CRC preset from filename header */
#endif
    mputs("rz\r");
    stohdr(0L);
    zshhdr(ZRQINIT, Txhdr);
}

#ifdef UNIX
struct stat filestat;
#endif

int
wcs(name)
char *name;
{
    int ret;

#ifdef UNIX
#ifdef NOCOPYTX
    secbuf = privsecbuf;
#endif
    if ((in=f_open(name, "r"))==NULL) {
        ++errcnt;
        return IZOK;    /* pass over it, there may be others */
    }
    fstat(fileno(in), &filestat);
#endif

// COLETTI mod (9/29/15): secbuf needs to be assigned prior to calling wctxpn(), if you want fullpath info to be sent
#ifdef NOCOPYTX
    secbuf = privsecbuf;
#endif

    Eofseen = 0;  vpos = 0;

    ret =  wctxpn(name);
#ifdef DIAGS
    vfile("wctxpn returned %d", ret);
#endif
    switch (ret) {
    case ZSKIP:
    case ZFERR:
        return IZOK;
    case IZOK:
        break;
    default:
        return IZERROR;
    }
    return 0;
}

/*
 * generate and transmit pathname block consisting of
 *  pathname (null terminated),
 */
wctxpn(name)
char *name;
{
    register char *p, *q;
    int n;

    if ( !Zmodem)
        if (getnak())
            return IZERROR;
    Zmodem = 1;

    for (p=name, q=secbuf ; *p; ) {
        switch(*q++ = *p++) {
// COLETTI mod (9/29/15): PicoDOS uses back-slahes, not forward-slashes
        case '\\':
            if (!Fullpath)
                q = secbuf;
        };
    }
    *q++ = 0;
#ifdef UNIX
    sprintf(q, "%lu %lo", filestat.st_size, filestat.st_mtime);
    q += strlen(q);
#else
#ifdef HAVE_STAT
    q += insertStat(q);
#endif
#endif
    *q++ = 0;
    *q++ = 0;
    n = q-secbuf;

    return zsendfile(secbuf, n);
}

getnak()
{
    register firstch;

#ifdef DIAGS
    vfile("entering getnak");
#endif
    Lastrx = 0;
    for (;;) {
        switch (firstch = readline(800)) {
        case ZPAD:
            if (getzrxinit())
                return IZERROR;
            return FALSE;
        case TIMEOUT:
            return TRUE;
        case CAN:
            if ((firstch = readline(20)) == CAN && Lastrx == CAN)
                return IZERROR;
        default:
            break;
        }
        Lastrx = firstch;
    }
}


#ifdef UNIX
void
zclose(status)
{
#ifdef DIAGS
    vfile("zclose: status=%d", status);
#endif
    if (in) {
        f_close(in);
#ifdef DIAGS
        vfile("f_close returned");
#endif
    } else {
#ifdef DIAGS
    vfile("file already closed!!");
#endif
    }

    in = 0;
}

int
zseek(n)
long n;
{
    clearerr(in);   /* Clear EOF */
    return (f_lseek(in, n, 0));
}

/* Fill buffer with blklen chars */
int
zfilbuf()
{
    size_t n;

#ifdef NOCOPYTX
    n = fread(secbuf=privsecbuf, 1, blklen, in);
#else
    n = fread(secbuf, 1, blklen, in);
#endif
    if (n < blklen)
        Eofseen = 1;
    return n;
}


usage()
{
    char **pp;

    f_printf(stderr, "Usage: isz [-l blklen] [-f] [-r] [-v] [-w window] file ...\n");
    exit(0);
}
#endif



/*
 * Get the receiver's init parameters
 */
getzrxinit()
{
    register triesleft;

    for (triesleft=10; --triesleft>=0; ) {

        switch (zgethdr()) {
        case ZCHALLENGE:    /* Echo receiver's challenge numbr */
            stohdr(Rxpos);
            zshhdr(ZACK, Txhdr);
            continue;
        case ZRINIT:
#ifdef LDP
            /* LDP protection active */
            Zldpactive = Rxhdr[ZF1] & CANLDP;
#ifdef DIAGS
            vfile("Zldpactive=%d", Zldpactive);
#endif
#endif
            Rxflags = 0377 & Rxhdr[ZF0];
            Txfcs32 = (Rxflags & CANFC32)?1:0;
            Zctlesc |= Rxflags & TESCCTL;
            Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
            if ( !(Rxflags & CANFDX))
                Txwindow = 0;
#ifdef DIAGS
            vfile("Rxbuflen=%d Tframlen=%u", Rxbuflen, Tframlen);
#endif
            /* Override to force shorter frame length */
            if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
                Rxbuflen = Tframlen;
            if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024))
                Rxbuflen = Tframlen;
#ifdef DIAGS
            vfile("Rxbuflen=%d", Rxbuflen);
#endif

            /* Set initial subpacket length */
            if (Rxbuflen && ((unsigned)blklen)>Rxbuflen)
                blklen = Rxbuflen;
#ifdef DIAGS
            vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
            vfile("Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
#endif
#ifdef ADDRLE
            if (Lztrans == ZTRLE && (Rxflags & CANRLE))
                Txfcs32 = 2;
            else
                Lztrans = 0;
#endif
#ifdef DIAGS
            vfile("Rxflags=%X Txfcs32=%d", Rxflags, Txfcs32);
#endif

            return IZOK;
        case ZCAN:
        case TIMEOUT:
            return IZERROR;
        default:
            zshhdr(ZNAK, Txhdr);
            continue;
        }
    }
    return IZERROR;
}


/* Send file name and related info */
zsendfile(buf, blen)
char *buf;
{
    register c;
#ifdef LDP
    long crc;
    char *p;
#endif

    for (;;) {
        stohdr(0L);
        Txhdr[ZF0] = Lzconv;    /* file conversion request */
#ifdef LDP
        Zcrcpreset = crc = 0xFFFFFFFFL;
        bytcnt = 0;
        if (Zldpactive)
            Txhdr[ZF3] |= ZSLDP;
#ifdef KKSIZE
        Txhdr[ZF3] |= ZSRWKK;
#endif
#endif
        zsbhdr(ZFILE, Txhdr);
        zsdata(buf, blen, ZCRCW);
#ifdef DIAGS
        vfile("zsendfile: %d %s", blen, buf);
#endif
//  flushmo(); exit(0); // ----------------------
#ifdef LDP
        if (Zldpactive) {
            for (p=buf, c=blen; --c >=0; ++p) {
                crc = UPDC32(*p, crc);
#ifdef DIAGS
                vfile("crc=%lX", crc);
#endif
            }
            for (p = zcpyrldp; *p; ++p)
                crc = UPDC32(*p, crc);
            Zcrcpreset = crc;
#ifdef DIAGS
            vfile("Zcrcpreset=%lX", Zcrcpreset);
#endif
        }
#endif
again:
        c = zgethdr();
        switch (c) {
        case ZRINIT:
#ifdef DIAGS
        vfile("spurious ZRINIT 1");
#endif
            continue;
        case IZERROR:
            continue;
        default:
        case ZCAN:
        case TIMEOUT:
        case ZABORT:
        case ZFIN:
            return IZERROR;
        case ZSKIP:
#ifdef DIAGS
            vfile("1zskip");
#endif
            zclose(IZERROR); return c;
        case ZRPOS:
            /*
             * Suppress zcrcw request otherwise triggered by
             * lastyunc==bytcnt
             */
            if (Rxpos && zseek(Rxpos))
                return IZERROR;
            Lastsync = (bytcnt = Txpos = Rxpos) -1;
            return zsendfdata();
        }
    }
}

#ifdef UNIX
char* pknames[] = {"CRC-16", "CRC-32", "RLE", ""};
#endif
/* Send the data in the file */
zsendfdata()
{
    register c, e, n;
    register newcnt;
    int junkcount;      /* Counts garbage chars received by TX */

    Lrxpos = 0;
    junkcount = 0;
    Beenhereb4 = FALSE;
    goto somemore;

waitack:
    junkcount = 0;
    c = getinsync(0);
gotack:
#ifdef DIAGS
    vfile("gotack: c=%d", c);
#endif
    switch (c) {
    default:
    case ZCAN:
#ifdef DIAGS
        vfile("zcan");
#endif
        zclose(IZERROR);
        return IZERROR;
    case ZSKIP:
#ifdef DIAGS
        vfile("2zskip");
#endif
        zclose(IZERROR);
        return c;
    case ZACK:
    case ZRPOS:
        break;
    case ZRINIT:
#ifdef DIAGS
        vfile("spurious ZRINIT 2");
#endif
        zclose(IZERROR);
        return IZOK;
    }
    while (checkline()) {
        switch (readline(1))
        {
        case XOFF:      /* Wait a while for an XON */
        case XOFF|0200:
            readline(100); continue;
        case CAN:
        case ZPAD:
            c = getinsync(1);
            goto gotack;
        }
    }

somemore:
    newcnt = Rxbuflen;
    Txwcnt = 0;
    e = ZCRCE;


    do {
        if (e == ZCRCE) {
            stohdr(Txpos);
            zsbhdr(ZDATA, Txhdr);
        }
        n = zfilbuf();
        if (Eofseen)
            e = ZCRCE;
        else if (junkcount > 3)
            e = ZCRCW;
        else if (bytcnt == Lastsync)
            e = ZCRCW;
        else if (Rxbuflen && (newcnt -= n) <= 0)
            e = ZCRCW;
        else if (Txwindow) {
#ifdef UNIX
            if (Verbose>1)
                f_printf(stderr, "Txwcnt=%lX\n", Txwcnt);
#endif
            if ((Txwcnt += n) >= Txwspac) {
                Txwcnt = 0;  e = ZCRCQ;
            }
        }
        else
            e = ZCRCG;
#ifdef UNIX
        if (Verbose>1)
            f_printf(stderr, "%7lX ZMODEM %s\n", Txpos, pknames[Crc32t&3]);
#endif
        zsdata(secbuf, n, e);
        bytcnt = Txpos += n;
        if (e == ZCRCW) {
            for (n = 20; --n >=0;)
                sendline(021);
            flushmo();
            goto waitack;
        }
        while (checkline()) {
            switch (readline(1))
            {
            case CAN:
            case ZPAD:
                c = getinsync(1);
                if (c == ZACK)
                    break;
#ifdef TCFLSH
                ioctl(wrfd, TCFLSH, 1);
#endif
                /* zcrce - dinna wanna starta ping-pong game */
                zsdata(secbuf, 0, ZCRCE);
                goto gotack;
            case XOFF:      /* Wait a while for an XON */
            case XOFF|0200:
                readline(100);
            case TIMEOUT:
#ifdef UNIX
                vfile("junktest: TIMEOUT");
#endif
                goto nojunk;
            default:
                ++junkcount;
            }
        }
nojunk:
        if (Txwindow) {
            while (((unsigned)(Txpos - Lrxpos)) >= Txwindow) {
                if (e != ZCRCQ)
                    zsdata(secbuf, 0, e = ZCRCQ);
                c = getinsync(1);
                if (c != ZACK) {
#ifdef TCFLSH
                    ioctl(wrfd, TCFLSH, 1);
#endif
                    zsdata(secbuf, 0, ZCRCE);
                    goto gotack;
                }
            }
        }
    } while (!Eofseen);

    stohdr(Txpos);
    zshhdr(ZEOF, Txhdr);
    for (;;) {
        switch (getinsync(0)) {
        case ZACK:
            continue;
        case ZRPOS:
            goto somemore;
        case ZRINIT:
#ifdef DIAGS
            vfile("ZRINIT on eof");
#endif

#ifdef LDP
#ifdef DIAGS
            vfile("ZGOTFILEOK=%d", Rxhdr[ZF2]);
#endif
            if ((!Zldpactive) || (Rxhdr[ZF2] & ZGOTFILEOK)) {  /* Last file received and closed */
                zclose(IZOK);
                return IZOK;
            } else {
                zclose(IZERROR);
                return IZERROR;
            }
#else
            zclose(IZOK);
            return IZOK;
#endif

        case ZSKIP:
#ifdef DIAGS
            vfile("3zskip");
#endif
            zclose(IZERROR);
            return c;
        default:
#ifdef DIAGS
            vfile("DEFAULT on eof");
#endif
            zclose(IZERROR);
            return IZERROR;
        }
    }
}

/*
 * Respond to receiver's complaint, get back in sync with receiver
 */
getinsync(flag)
{
    register c;

    for (;;) {
        c = zgethdr();
        switch (c) {
        case ZCAN:
        case ZABORT:
        case ZFIN:
        case TIMEOUT:
            return IZERROR;
        case ZRPOS:
#if 1
refoo:          c = readline(1);
            switch (c) {
            case '*':
                continue;
            case 015:  case 012: case 021: case 0221:
                goto refoo;
            default:
                break;
            }
#endif
            /* ************************************* */
            /*  If sending to a buffered modem, you  */
            /*   might send a break at this point to */
            /*   dump the modem's buffer.        */
            if (zseek(Rxpos))
                return IZERROR;
            Eofseen = 0;
            bytcnt = Lrxpos = Txpos = Rxpos;
            if (Lastsync == Rxpos) {
                if (++Beenhereb4 > 4)
                    if (blklen > 64)
                        blklen /= 2;
            }
            Lastsync = Rxpos;
            stohdr(Txpos);      // CAF 9-7-2011
            return ZRPOS;
        case ZACK:
            Lrxpos = Rxpos;
            if (flag || Txpos == Rxpos)
                return ZACK;
            continue;
        case ZRINIT:
#ifdef DIAGS
            vfile("zrinit2");
#endif
            return c;
        case ZSKIP:
#ifdef DIAGS
            vfile("4zskip");
#endif
            return c;
        case IZERROR:
        default:
            zshhdr(ZNAK, Txhdr);
            continue;
        }
    }
}


/* Say "bibi" to the receiver, try to do it cleanly */
void
saybibi()
{
    for (;;) {
        stohdr(0L);     /* CAF Was zsbhdr - minor change */
        zshhdr(ZFIN, Txhdr);    /*  to make debugging easier */
        switch (zgethdr()) {
        case ZFIN:
            sendline('O'); sendline('O');
#ifdef FLUSH
            flushmo();
#endif
        /*FALLTHRU*/
        case ZCAN:
        case TIMEOUT:
            return;
        }
    }
}

/* End of isz.c */







// -------------- izm.c

/*
 *   I Z M . C
 *    ZMODEM protocol primitives
 *  Copyright 2004 2011 Omen Technology INC All Rights Reserved
 *     This is UNPUBLISHED PROPRIETARY SOURCE CODE of Omen Technology INC.
 *     The Copyright notice above does not evidence any actual or intended
 *     publication such source code.
 *
 * Entry point Functions:
 *  zsbhdr(type, hdr) send binary header
 *  zshhdr(type, hdr) send hex header
 *  zgethdr() receive header - binary or hex
 *  zsdata(buf, len, frameend) send data
 *  zrdata(buf, len) receive data
 *  stohdr(pos) store position data in Txhdr
 *  long rclhdr(hdr) recover position offset from header
 */

#ifndef UNSL
#define UNSL
#endif
int zdlread(), noxrd7(), zrbhdr(), zrhhdr(), zgethex(), zgeth1();
int zrdat32(), zrbhdr32();

/* Globals used by ZMODEM functions */
int Rxframeind;     /* ZBIN ZBIN32, ZHEX, or ZBINR32 type of frame received */
int Rxtype;     /* Type of header received */
int Rxcount;        /* Count of data bytes received */
long bytcnt;
char Rxhdr[4];      /* Received header */
char Txhdr[8];      /* Transmitted header */
long Rxpos;     /* Received file position */
long Txpos;     /* Transmitted file position */
int Txfcs32;        /* TURE means send binary frames with 32 bit FCS */
int Crc32t;     /* Display flag indicating 32 bit CRC being sent */

#ifdef LDP
int Zldpactive; /* LDP protection active */
char Zaddr8[8]; /* Array for address CRC bias */
unsigned long Zcrcpreset;   /* CRC preset from filename header */
unsigned long Zcrcinit; /* CRC init for zrdata zsdata */
char zcpyrldp[] = "Copyright 2002 Omen Technology INC All Rights Reserved";
#endif


#ifdef ZSTAB
unsigned char zstable[256] = {
    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
    0120,0121,0,0123,0,0,0,0, 0130,0,0,0,0,0,0,0,

    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,

    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
    0320,0321,0,0323,0,0,0,0, 0,0,0,0,0,0,0,0,

    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,
#ifdef NOFF
    ZRUB1
#else
    0
#endif
};
#endif


#ifdef NOCOPYTX
char *secbuf;
#ifdef BOTH
no this is not supported
#endif
#else
#ifdef KKSIZE
char secbuf[KKSIZE];
#else
char secbuf[1025];
#endif
#endif


#ifdef DIAGS
static char *frametypes[] = {
    "Carrier Lost",     /* -3 */
    "TIMEOUT",      /* -2 */
    "IZERROR",      /* -1 */
#define FTOFFSET 3
    "ZRQINIT",
    "ZRINIT",
    "ZSINIT",
    "ZACK",
    "ZFILE",
    "ZSKIP",
    "ZNAK",
    "ZABORT",
    "ZFIN",
#ifdef UNIX
    "\033[7mZRPOS\033[0m",
#else
    "ZRPOS",
#endif
    "ZDATA",
    "ZEOF",
    "ZFERR",
    "ZCRC",
    "ZCHALLENGE",
    "ZCOMPL",
    "ZCAN",
    "ZFREECNT",
    "ZCOMMAND",
    "xxxxx"
#define FRTYPES 22  /* Total number of frame types in this array */
            /*  not including psuedo negative entries */
};

static char badcrc[] = "Bad CRC";
#endif /* DIAGS */

/* Send ZMODEM binary header hdr of type type */
void
zsbh32(hdr, type)
register char *hdr;
{
    register int n;
    register UNSL long crc;

    sendline((Crc32t=Txfcs32)==2 ? ZBINR32:ZBIN32);  zsendline(type);
    crc = 0xFFFFFFFFL; crc = UPDC32(type, crc);

    for (n=4; --n >= 0; ++hdr) {
        crc = UPDC32((0377 & *hdr), crc);
        zsendline(*hdr);
    }
    crc = ~crc;
    for (n=4; --n >= 0;) {
        zsendline((int)crc);
        crc >>= 8;
    }
}

/* Send ZMODEM binary header hdr of type type */
void
zsbhdr(type, hdr)
register char *hdr;
{
    register int n;
    register unsigned short crc;

#ifdef DIAGS
    vfile("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
#endif
    sendline(ZPAD); sendline(ZDLE);

    Crc32t=Txfcs32;
    if (Crc32t)
        zsbh32(hdr, type);
    else
    {
        sendline(ZBIN); zsendline(type); crc = updcrc(type, 0);

        for (n=4; --n >= 0; ++hdr) {
            zsendline(*hdr);
            crc = updcrc((0377& *hdr), crc);
        }
        crc = updcrc(0,updcrc(0,crc));
        zsendline(crc>>8);
        zsendline(crc);
    }
}



/* Send ZMODEM HEX header hdr of type type */
void
zshhdr(type, hdr)
register char *hdr;
{
    register int n;
    register unsigned short crc;

#ifdef DIAGS
    vfile("zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
#endif
    sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX);
    zputhex(type);
    Crc32t = 0;

    crc = updcrc(type, 0);
    for (n=4; --n >= 0; ++hdr) {
        zputhex(*hdr); crc = updcrc((0377 & *hdr), crc);
    }
    crc = updcrc(0,updcrc(0,crc));
    zputhex(crc>>8); zputhex(crc);

    /* Make it printable on remote machine */
    sendline(015); sendline(0212);
    /*
     * Uncork the remote in case a fake XOFF has stopped data flow
     */
    if (type != ZFIN && type != ZACK)
        sendline(021);
#ifdef FLUSH
    flushmo();
#endif
}

/*
 * Send binary array buf of length length, with ending ZDLE sequence frameend
 */
#ifdef DIAGS
static char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"};
#endif

void
zsda32(buf, length, frameend)
#ifndef MANYREGS
register
#endif
 unsigned char *buf;
register length;
{
    register int c;
    register UNSL long crc;
#ifdef ZSTAB
    register d;
#endif
#ifdef MANYREGS
    register unsigned char *p;
    register unsigned long *pcrctab;

    pcrctab = icr3tab;
    p = buf;
#endif

    crc = 0xFFFFFFFFL;
#ifdef LDP
    if (Zldpactive) {
        stohdr(bytcnt);
        for (crc=Zcrcpreset, c=0; c<8; ++c) {
#ifndef DIAGS
            vfile("c=%d Txhdr[c]=%d crc=%lX", c, Txhdr[c], crc);
#endif
            crc = UPDC32(Txhdr[c], crc);
        }
    }
#ifndef DIAGS
    vfile("Zcrcinit=%lX", Zcrcinit);
#endif
#endif

#ifdef MANYREGS
    for (;--length >= 0;) {
        c = *p++ & 0377;
    /* UPDC32(b, c) (icr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)) */
    crc = pcrctab[(crc ^ c) & 0xff] ^ ((crc >> 8) & 0x00FFFFFF);
#else
    for (;--length >= 0; ++buf) {
        c = *buf & 0377;
        crc = UPDC32(c, crc);
#endif
#ifdef ZSTAB
        if ((d = zstable[c])) {
            sendline(ZDLE); c = d;
        }
        sendline(c);
#else       /* ZSTAB */
#ifndef NOFF
        if (c & 0140)
            sendline(c);
        else
#endif
            zsendline(c);
#endif      /* ZSTAB */
    }
    sendline(ZDLE); sendline(frameend);
    crc = UPDC32(frameend, crc);

    crc = ~crc;
    for (length=4; --length >= 0;) {
        zsendline((int)crc);  crc >>= 8;
    }
}

void
zsdata(buf, length, frameend)
register char *buf;
{
    register unsigned short crc;
#ifdef LDP
    register m;
#endif

#ifdef DIAGS
    vfile("zsdata: %d %s", length, Zendnames[frameend-ZCRCE&3]);
#endif
    switch (Crc32t) {
    case 1:
        zsda32(buf, length, frameend);  break;
#ifdef ADDRLE
    case 2:
        zsdar32(buf, length, frameend);  break;
#endif
    default:
        crc = 0;
#ifdef LDP
        if (Zldpactive) {
            stohdr(bytcnt);
            for (crc=0xFFFF, m=0; m<4; ++m) {
#ifdef DIAGS
                vfile("m=%d Txhdr[m]=%d crc=%X", m, Txhdr[m], crc);
#endif
                crc = updcrc(0377 & Txhdr[m], crc);
            }
        }
#endif
        for (;--length >= 0; ++buf) {
            zsendline(*buf); crc = updcrc((0377 & *buf), crc);
        }
        sendline(ZDLE); sendline(frameend);
        crc = updcrc(frameend, crc);

        crc = updcrc(0,updcrc(0,crc));
        zsendline(crc>>8); zsendline(crc);
        break;
    }
    if (frameend == ZCRCW) {
        sendline(XON);
#ifdef FLUSH
        flushmo();
#endif
    }
#ifdef FLUSH
    else if (frameend != ZCRCG)
        flushmoc();
#endif
}

/*
 * Receive array buf of max length with ending ZDLE sequence
 *  and CRC.  Returns the ending character or error code.
 *  NB: On errors may store length+1 bytes!
 */
zrdata(buf, length)
register char *buf;
{
    register int c;
    register unsigned short crc;
    register char *end;
    register int d;

    switch (Rxframeind) {
    case ZBIN32:
        return zrdat32(buf, length);
#ifdef ADDRLE
    case ZBINR32:
        return zrdatr32(buf, length);
#endif
    }

    crc = 0;
#ifdef LDP
    if (Zldpactive) {
        stohdr(bytcnt);
        for (crc=0xFFFF, c=0; c<4; ++c) {
#ifdef DIAGS
            vfile("c=%d Txhdr[c]=%d crc=%X", c, Txhdr[c], crc);
#endif
            crc = updcrc(0377 & Txhdr[c], crc);
        }
    }
#endif
    Rxcount = 0;  end = buf + length;
    while (buf <= end) {
        if ((c = zdlread()) & ~0377) {
crcfoo:
            switch (c) {
            case GOTCRCE:
            case GOTCRCG:
            case GOTCRCQ:
            case GOTCRCW:
                crc = updcrc(((d=c)&0377), crc);
                if ((c = zdlread()) & ~0377)
                    goto crcfoo;
                crc = updcrc(c, crc);
                if ((c = zdlread()) & ~0377)
                    goto crcfoo;
                crc = updcrc(c, crc);
                if (crc & 0xFFFF) {
#ifdef DIAGS
                    zbitch(badcrc);
#endif
                    return IZERROR;
                }
                Rxcount = length - (end - buf);
#ifdef DIAGS
                vfile("zrdata: %d  %s", Rxcount,
                 Zendnames[d-GOTCRCE&3]);
#endif
                return d;
            case GOTCAN:
#ifdef UNIX
                zbitch("Sender Canceled");
#endif
                return ZCAN;
            case TIMEOUT:
#ifdef UNIX
                zbitch("TIMEOUT");
#endif
                return c;
            default:
#ifdef UNIX
                zbitch("Bad data subpacket");
#endif
                return c;
            }
        }
        *buf++ = c;
        crc = updcrc(c, crc);
    }
#ifdef UNIX
    zbitch("Data subpacket too long");
#endif
    return IZERROR;
}

zrdat32(buf, length)
register char *buf;
{
    register int c;
    register UNSL long crc;
    register char *end;
    register int d;

#ifdef LDP
    if (Zldpactive) {
        stohdr(bytcnt);
        for (crc=Zcrcpreset, c=0; c<8; ++c) {
#ifndef DIAGS
            vfile("c=%d Txhdr[c]=%d crc=%lX", c, Txhdr[c], crc);
#endif
            crc = UPDC32(Txhdr[c], crc);
        }
    } else
        crc = 0xFFFFFFFFL;
#ifndef DIAGS
    vfile("zrdata: bytcnt=%lX Zcrcinit=%lX", (long) bytcnt, Zcrcinit);
#endif
#else
    crc = 0xFFFFFFFFL;
#endif

    Rxcount = 0;  end = buf + length;
    while (buf <= end) {
        if ((c = zdlread()) & ~0377) {
crcfoo:
            switch (c) {
            case GOTCRCE:
            case GOTCRCG:
            case GOTCRCQ:
            case GOTCRCW:
                d = c;  c &= 0377;
                crc = UPDC32(c, crc);
                if ((c = zdlread()) & ~0377)
                    goto crcfoo;
                crc = UPDC32(c, crc);
                if ((c = zdlread()) & ~0377)
                    goto crcfoo;
                crc = UPDC32(c, crc);
                if ((c = zdlread()) & ~0377)
                    goto crcfoo;
                crc = UPDC32(c, crc);
                if ((c = zdlread()) & ~0377)
                    goto crcfoo;
                crc = UPDC32(c, crc);
                if (crc != 0xDEBB20E3) {
#ifdef DIAGS
                    zbitch(badcrc);
#endif
                    return IZERROR;
                }
                Rxcount = length - (end - buf);
#ifdef DIAGS
                vfile("zrdat32: %d %s", Rxcount,
                 Zendnames[d-GOTCRCE&3]);
#endif
                return d;
            case GOTCAN:
#ifdef UNIX
                zbitch("Sender Canceled");
#endif
                return ZCAN;
            case TIMEOUT:
#ifdef UNIX
                zbitch("TIMEOUT");
#endif
                return c;
            default:
#ifdef UNIX
                zbitch("Bad data subpacket");
#endif
                return c;
            }
        }
        *buf++ = c;
        crc = UPDC32(c, crc);
    }
#ifdef UNIX
    zbitch("Data subpacket too long");
#endif
    return IZERROR;
}


/*
 * Read a ZMODEM header to hdr, either binary or hex.
 *  On success, set Rxpos and return type of header.
 *   Otherwise return negative on error.
 *   Return  IZERROR instantly if ZCRCW sequence, for fast error recovery.
 */
int
zgethdr()
{
    register int c, n, cancount;

    n = Zrwindow + 19200;   /* Max bytes before start of frame */
    Rxframeind = Rxtype = 0;

startover:
    cancount = 5;
again:
    /* Return immediate IZERROR if ZCRCW sequence seen */
    switch (c = readline(Rxtimeout)) {
    case TIMEOUT:
        goto fifi;
    case CAN:
gotcan:
        if (--cancount <= 0) {
            c = ZCAN; goto fifi;
        }
        switch (c = readline(1)) {
        case TIMEOUT:
            goto again;
        case ZCRCW:
            c = IZERROR;
        /*FALLTHRU*/
            goto fifi;
        default:
            break;
        case CAN:
            if (--cancount <= 0) {
                c = ZCAN; goto fifi;
            }
            goto again;
        }
    /*FALLTHRU*/
    default:
agn2:
        if ( --n == 0) {
#ifdef UNIX
            zbitch("Garbage count exceeded");
#endif
            return(IZERROR);
        }
#ifdef UNIX
        fflush(stderr);
#endif
        goto startover;
    case ZPAD|0200:     /* This is what we want. */
    case ZPAD:      /* This is what we want. */
        break;
    }
    cancount = 5;
splat:
    switch (c = noxrd7()) {
    case ZPAD:
        goto splat;
    case TIMEOUT:
        goto fifi;
    default:
        goto agn2;
    case ZDLE:      /* This is what we want. */
        break;
    }

    switch (c = noxrd7()) {
    case TIMEOUT:
        goto fifi;
    case ZBIN:
        Rxframeind = c;
        c =  zrbhdr();
        break;
#ifdef ADDRLE
    case ZBINR32:
#endif
    case ZBIN32:
        Rxframeind = c;
        c =  zrbhdr32();
        break;
    case ZHEX:
        Rxframeind = c;
        c =  zrhhdr();
        break;
    case CAN:
        goto gotcan;
    default:
        goto agn2;
    }
    Rxpos = Rxhdr[ZP3] & 0377;
    Rxpos = (Rxpos<<8) + (Rxhdr[ZP2] & 0377);
    Rxpos = (Rxpos<<8) + (Rxhdr[ZP1] & 0377);
    Rxpos = (Rxpos<<8) + (Rxhdr[ZP0] & 0377);
fifi:
    switch (c) {
    case GOTCAN:
        c = ZCAN;
    /*FALLTHRU*/
#ifdef UNIX
    case ZNAK:
    case ZCAN:
    case IZERROR:
    case TIMEOUT:
        zperr("Zgethdr: got %s", frametypes[c+FTOFFSET]);
    /*FALLTHRU*/
#endif
    default:
#ifdef DIAGS
        if (c >= -3 && c <= FRTYPES)
            vfile("zgethdr: %s %lx", frametypes[c+FTOFFSET], Rxpos);
        else
            vfile("zgethdr: %d %lx", c, Rxpos);
#endif
        break;
    }
    return c;
}

/* Receive a binary style header (type and position) */
zrbhdr()
{
    register char *hdr = Rxhdr;
    register int c, n;
    register unsigned short crc;

    if ((c = zdlread()) & ~0377)
        return c;
    Rxtype = c;
    crc = updcrc(c, 0);

    for (n=4; --n >= 0; ++hdr) {
        if ((c = zdlread()) & ~0377)
            return c;
        crc = updcrc(c, crc);
        *hdr = c;
    }
    if ((c = zdlread()) & ~0377)
        return c;
    crc = updcrc(c, crc);
    if ((c = zdlread()) & ~0377)
        return c;
    crc = updcrc(c, crc);
    if (crc & 0xFFFF) {
#ifdef DIAGS
        zbitch(badcrc);
#endif
        return IZERROR;
    }
    return Rxtype;
}

/* Receive a binary style header (type and position) with 32 bit FCS */
zrbhdr32()
{
    register char *hdr = Rxhdr;
    register int c, n;
    register UNSL long crc;

    if ((c = zdlread()) & ~0377)
        return c;
    Rxtype = c;
    crc = 0xFFFFFFFFL; crc = UPDC32(c, crc);
#ifdef DEBUGZ
    vfile("zrbhdr32 c=%X  crc=%lX", c, crc);
#endif

    for (n=4; --n >= 0; ++hdr) {
        if ((c = zdlread()) & ~0377)
            return c;
        crc = UPDC32(c, crc);
        *hdr = c;
#ifdef DEBUGZ
        vfile("zrbhdr32 c=%X  crc=%lX", c, crc);
#endif
    }
    for (n=4; --n >= 0;) {
        if ((c = zdlread()) & ~0377)
            return c;
        crc = UPDC32(c, crc);
#ifdef DEBUGZ
        vfile("zrbhdr32 c=%X  crc=%lX", c, crc);
#endif
    }
    if (crc != 0xDEBB20E3) {
#ifdef DIAGS
        zbitch(badcrc);
#endif
        return IZERROR;
    }
    return Rxtype;
}


/* Receive a hex style header (type and position) */
zrhhdr()
{
    register int c;
    register char *hdr = Rxhdr;
    register unsigned short crc;
    register int n;

    if ((c = zgethex()) < 0)
        return c;
    Rxtype = c;
    crc = updcrc(c, 0);

    for (n=4; --n >= 0; ++hdr) {
        if ((c = zgethex()) < 0)
            return c;
        crc = updcrc(c, crc);
        *hdr = c;
    }
    if ((c = zgethex()) < 0)
        return c;
    crc = updcrc(c, crc);
    if ((c = zgethex()) < 0)
        return c;
    crc = updcrc(c, crc);
    if (crc & 0xFFFF) {
#ifdef DIAGS
        zbitch(badcrc);
#endif
        return IZERROR;
    }
    switch ( c = readline(1)) {
    case 0215:
    case 015:
        /* Throw away possible cr/lf */
        c = readline(1);
    }
    return Rxtype;
}

/* Send a byte as two hex digits */
void
zputhex(c)
register int c;
{
    static char digits[]    = "0123456789abcdef";

#ifdef DIAGS
    if (Verbose>8)
        vfile("zputhex: %02X", c & 0377);
#endif
    sendline(digits[(c&0xF0)>>4]);
    sendline(digits[(c)&0xF]);
}

/*
 * Send character c with ZMODEM escape sequence encoding.
 *  Escape DLE, XON, XOFF.
 */
void
zsendline(c)
register c;
#ifdef ZSTAB
{
    register d;

    c &= 0377;
    if ((d = zstable[c])) {
        sendline(ZDLE); c = d;
    }
    sendline(c);
}
#else
{
#ifdef NOFF
    c &= 0377;
    if (c == 0377) {
            sendline(ZDLE);
            c = ZRUB1;  /* Passes the 0140 mask below !! */
    }
#endif
    /* Quick check for non control characters */
    if (c & 0140)
        sendline(c);
    else {
        switch (c &= 0377) {
        case ZDLE:
        case 020:
        case 021:
        case 023:
        case 0220:
        case 0221:
        case 0223:
            sendline(ZDLE);
            c ^= 0100;
            sendline(c);
            break;
        default:
            if (Zctlesc) {
                sendline(ZDLE);
                c ^= 0100;
            }
            sendline(c);
        }
    }
}
#endif

/* Decode two lower case hex digits into an 8 bit byte value */
zgethex()
{
    register int c;

    c = zgeth1();
#ifdef DIAGS
    if (Verbose>8)
        vfile("zgethex: %02X", c);
#endif
    return c;
}
zgeth1()
{
    register int c, n;

    if ((c = noxrd7()) < 0)
        return c;
    n = c - '0';
    if (n > 9)
        n -= ('a' - ':');
    if (n & ~0xF)
        return IZERROR;
    if ((c = noxrd7()) < 0)
        return c;
    c -= '0';
    if (c > 9)
        c -= ('a' - ':');
    if (c & ~0xF)
        return IZERROR;
    c += (n<<4);
    return c;
}

/*
 * Read a byte, checking for ZMODEM escape encoding
 *  including CAN*5 which represents a quick abort
 */
zdlread()
{
    register int c;

again:
    /* Quick check for non control characters */
    if ((c = readline(Rxtimeout)) & 0140)
        return c;
    switch (c) {
    case ZDLE:
        break;
    case 023:
    case 0223:
    case 021:
    case 0221:
        goto again;
    default:
        if (Zctlesc && !(c & 0140)) {
            goto again;
        }
        return c;
    }
again2:
    if ((c = readline(Rxtimeout)) < 0)
        return c;
    if (c == CAN && (c = readline(Rxtimeout)) < 0)
        return c;
    if (c == CAN && (c = readline(Rxtimeout)) < 0)
        return c;
    if (c == CAN && (c = readline(Rxtimeout)) < 0)
        return c;
    switch (c) {
    case CAN:
        return GOTCAN;
    case ZCRCE:
    case ZCRCG:
    case ZCRCQ:
    case ZCRCW:
        return (c | GOTOR);
        /* DO NOT REMOVE THIS ENTRY!!! */
    case ZRUB0:
        return 0177;
        /* DO NOT REMOVE THIS ENTRY!!! (used for telnet) */
    case ZRUB1:
        return 0377;
    case 023:
    case 0223:
    case 021:
    case 0221:
        goto again2;
    default:
        if (Zctlesc && ! (c & 0140)) {
            goto again2;
        }
        if ((c & 0140) ==  0100)
            return (c ^ 0100);
        break;
    }
#ifdef DIAGS
    if (Verbose>1)
        zperr("Bad escape sequence %x", c);
#endif
    return IZERROR;
}

/*
 * Read a character from the modem line with timeout.
 *  Eat parity, XON and XOFF characters.
 */
noxrd7()
{
    register int c;

    for (;;) {
        if ((c = readline(Rxtimeout)) < 0)
            return c;
        switch (c &= 0177) {
        case XON:
        case XOFF:
            continue;
        default:
            if (Zctlesc && !(c & 0140))
                continue;
        /*FALLTHRU*/
        case '\r':
        case '\n':
        case ZDLE:
            return c;
        }
    }
}

/* Store long integer pos in Txhdr */
void
stohdr(pos)
long pos;
{
    Txhdr[ZP0] = (char) pos;
    Txhdr[ZP1] = (char) (pos>>8);
    Txhdr[ZP2] = (char) (pos>>16);
    Txhdr[ZP3] = (char) (pos>>24);
}

/* Recover a long integer from a header */
long
rclhdr(hdr)
register char *hdr;
{
    register long l;

    l = (hdr[ZP3] & 0377);
    l = (l << 8) | (hdr[ZP2] & 0377);
    l = (l << 8) | (hdr[ZP1] & 0377);
    l = (l << 8) | (hdr[ZP0] & 0377);
    return l;
}

void
mputs(s)
register char *s;
{
    while (*s)
        sendline(*s++);
#ifdef FLUSH
    flushmo();
#endif
}

/* send cancel string to get the other end to shut up */
void
canit()
{
    static char canistr[] = {
     24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
    };

#ifdef DIAGS
    vfile("Canit");
#endif
    mputs(canistr);
    purgeline();
}

/* End of zm.c */




//--------- izmr.c
/*
 * File: zmr.c
 * Copyright 1988, 2002 Omen Technology Inc All Rights Reserved
 *
 *
 *
 * This module implements ZMODEM Run Length Encoding, an
 * extension that was not funded by the original Telenet
 * development contract.
 *
 *  This software may be freely used for educational (didactic
 *  only) purposes.  This software may also be freely used to
 *  support file transfer operations to or from licensed Omen
 *  Technology products.  Use with other commercial or shareware
 *  programs (Crosstalk, Procomm, etc.) REQUIRES REGISTRATION.
 *
 *  Any programs which use part or all of this software must be
 *  provided in source form with this notice intact except by
 *  written permission from Omen Technology Incorporated.
 *
 * Use of this software for commercial or administrative purposes
 * except when exclusively limited to interfacing Omen Technology
 * products requires a per port license payment of $20.00 US per
 * port (less in quantity).  Use of this code by inclusion,
 * decompilation, reverse engineering or any other means
 * constitutes agreement to these conditions and acceptance of
 * liability to license the materials and payment of reasonable
 * legal costs necessary to enforce this license agreement.
 *
 *
 *      Omen Technology Inc
 *      Post Office Box 1314
 *      Hillsboro OR 97123
 *
 *  This code is made available in the hope it will be useful,
 *  BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
 *  DAMAGES OF ANY KIND.
 *
 *  ZMODEM RLE compression and decompression functions
 */

/* Send data subpacket RLE encoded with 32 bit FCS */
void zsdar32(buf, length, frameend)
char *buf;
{
    register int c, l, n;
    register long crc;

#ifdef DIAGS
    vfile("zsdatr32: %d %X", length, frameend);
#endif
    crc = 0xFFFFFFFFL;  l = *buf++ & 0377;
    for (n = 0; --length >= 0; ++buf) {
        if ((c = *buf & 0377) == l && n < 126 && length>0) {
            ++n;  continue;
        }
        switch (n) {
        case 0:
            zsendline(l);
            crc = UPDC32(l, crc);
            if (l == ZRESC) {
                zsendline(0100); crc = UPDC32(0100, crc);
            }
            l = c; break;
        case 1:
            if (l != ZRESC) {
                zsendline(l); zsendline(l);
                crc = UPDC32(l, crc);
                crc = UPDC32(l, crc);
                n = 0; l = c; break;
            }
            /* **** FALL THRU TO **** */
        default:
            zsendline(ZRESC); crc = UPDC32(ZRESC, crc);
            if (l == 040 && n < 34) {
                n += 036;
                zsendline(n); crc = UPDC32(n, crc);
            }
            else {
                n += 0101;
                zsendline(n); crc = UPDC32(n, crc);
                zsendline(l); crc = UPDC32(l, crc);
            }
            n = 0; l = c; break;
        }
    }
    sendline(ZDLE); sendline(frameend);
    crc = UPDC32(frameend, crc);

    crc = ~crc;
    for (length=4; --length >= 0;) {
        zsendline((int)crc);  crc >>= 8;
    }
}


/* Receive data subpacket RLE encoded with 32 bit FCS */
zrdatr32(buf, length)
register char *buf;
{
    register int c;
    register long crc;
    register char *end;
    register int d;

    crc = 0xFFFFFFFFL;  Rxcount = 0;  end = buf + length;
    d = 0;  /* Use for RLE decoder state */
    while (buf <= end) {
        if ((c = zdlread()) & ~0377) {
crcfoo:
            switch (c) {
            case GOTCRCE:
            case GOTCRCG:
            case GOTCRCQ:
            case GOTCRCW:
                d = c;  c &= 0377;
                crc = UPDC32(c, crc);
                if ((c = zdlread()) & ~0377)
                    goto crcfoo;
                crc = UPDC32(c, crc);
                if ((c = zdlread()) & ~0377)
                    goto crcfoo;
                crc = UPDC32(c, crc);
                if ((c = zdlread()) & ~0377)
                    goto crcfoo;
                crc = UPDC32(c, crc);
                if ((c = zdlread()) & ~0377)
                    goto crcfoo;
                crc = UPDC32(c, crc);
                if (crc != 0xDEBB20E3) {
#ifdef DIAGS
                    zbitch(badcrc);
#endif
                    return IZERROR;
                }
                Rxcount = length - (end - buf);
#ifdef DIAGS
                vfile("zrdatr32: %d %s", Rxcount,
                  Zendnames[d-GOTCRCE&3]);
#endif
                return d;
            case GOTCAN:
                zbitch("Sender Canceled");
                return ZCAN;
            case TIMEOUT:
                zbitch("TIMEOUT");
                return c;
            default:
                zbitch("Bad data subpacket");
                return c;
            }
        }
        crc = UPDC32(c, crc);
        switch (d) {
        case 0:
            if (c == ZRESC) {
                d = -1;  continue;
            }
            *buf++ = c;  continue;
        case -1:
            if (c >= 040 && c < 0100) {
                d = c - 035; c = 040;  goto spaces;
            }
            if (c == 0100) {
                d = 0;
                *buf++ = ZRESC;  continue;
            }
            d = c;  continue;
        default:
            d -= 0100;
            if (d < 1)
                goto badpkt;
spaces:
            if ((buf + d) > end)
                goto badpkt;
            while ( --d >= 0)
                *buf++ = c;
            d = 0;  continue;
        }
    }
badpkt:
    zbitch("Data subpacket too long");
    return IZERROR;
}

/* End of izmr.c */

//#endif
