home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / COMM / MISC / SRC26_2.ZIP / SRC / XMODEM.C < prev   
Encoding:
C/C++ Source or Header  |  1990-07-04  |  35.2 KB  |  1,200 lines

  1. /*
  2.  * xmodem.c: hterm xmodem module
  3.  *
  4.  * converted from xmodem 3.6 4/88 by Grandi
  5.  * NO COPYRIGHT.
  6.  *
  7.  * Edition History:
  8.  * 1.1 89/09/20 mnr    initial port to hterm
  9.  * 1.2 89/09/22 Halca.Hirano brush up
  10.  *    1) remove MODEM7 protocol for simplisity
  11.  *    2) rewrite file receive entirely
  12.  *    3) full automatic receiving protocol & option detection
  13.  * 1.3 89/09/25 Halca.Hirano
  14.  *    fix turboC compile error
  15.  *    ---- V2.4.0 distribution ----
  16.  * 1.4 89/10/10 Halca.Hirano
  17.  *    fix send filename building bug
  18.  * 1.5 89/10/14 Halca.Hirano
  19.  *    set 8 bit character length automatically (Thanks shikida@titech)
  20.  * 1.6 89/12/06 Halca.Hirano
  21.  *    fix parity change bug
  22.  * 1.7 89/12/12 Halca.Hirano
  23.  *    move xgetnext() in file.c
  24.  *    all public functions are callable from comm. mode as well as from setup.
  25.  * 1.8 90/01/16 Halca.Hirano
  26.  *    get rid of bugs which cause 'devide by zero' error when sending null file
  27.  * 1.9 90/06/23 Halca.Hirano
  28.  *    fix expected file size bug for file receiving
  29.  *
  30.  * $Header: xmodem.cv  1.17  90/07/04 18:09:48  hirano  Exp $
  31.  */
  32.  
  33. /* original header is here. */
  34.  
  35. /*
  36.  *  XMODEM -- Implements the Christensen XMODEM protocol, 
  37.  *            for packetized file up/downloading.    
  38.  *
  39.  *    See the README file for some notes on SYS V adaptations.
  40.  *    The program has been successfully run on VAXes (4.3BSD) and SUN-3/4s
  41.  *    (SunOS 3.x) against MEX-PC and ZCOMM/DSZ.
  42.  *
  43.  *  See the README and update.doc files for history and change notes.
  44.  *
  45.  *  Please send bug fixes, additions and comments to:
  46.  *    {ihnp4,ncar}!noao!grandi   grandi@noao.arizona.edu
  47.  */
  48.  
  49.  
  50. #include "option.h"
  51. #ifdef XMODEM
  52.  
  53. #include <stdio.h>
  54. #include <ctype.h>
  55. #include <setjmp.h>
  56. #include <fcntl.h>
  57. #include <time.h>
  58. #include <io.h>
  59. #ifdef __TURBOC__
  60. #include <dir.h>
  61. #endif
  62. #if !defined(__TURBOC__) || __TURBOC__ >= 0x0200
  63. #include <sys/types.h>
  64. #endif
  65. #include <sys/stat.h>
  66. #include <string.h>
  67. #include "config.h"
  68. #include "hterm.h"
  69. #include "default.h"
  70. #include "global.h"
  71.  
  72. #define         XVERSION    36    /* Version Number */
  73.  
  74. #define      FALSE      0
  75. #define      TRUE       1
  76.  
  77.  
  78. /*  ASCII Constants  */
  79. #define         STX    002
  80. #define         ETX    003
  81. #define      EOT    004
  82. #define      ACK      006
  83. #define      NAK      025
  84. #define         SYN    026
  85.  
  86. /*  XMODEM Constants  */
  87. #define      TIMEOUT      -1
  88. #define      ERRORMAX      10    /* maximum errors tolerated while transferring a packet */
  89. #define      Y_TO_X_SW    4     /* errors to switch Y to X on sending Y filename */
  90. #define      WAITFIRST  1     /* seconds between startup characters in read */
  91. #define      STERRORMAX    60    /* maximum "errors" tolerated in read startup */
  92. #define      CRCSWMAX    30    /* maximum time to try CRC mode before switching */
  93. #define      NAKMAX    120   /* maximum times to wait for initial NAK when sending */
  94. #define      RETRYMAX      5     /* maximum retries to be made certain handshaking routines */
  95. #define      KSWMAX    5     /* maximum errors before switching to 128 byte packets */
  96. #define      EOTMAX    10    /* maximum times sender will send an EOT to end transfer */
  97. #define      SLEEPNUM    100   /* target number of characters to collect during sleepy time */
  98. #define         BBUFSIZ    1024  /* buffer size */
  99. #define      NAMSIZ    11    /* length of a CP/M file name string */
  100. #define         CTRLZ    032   /* CP/M EOF for text (usually!) */
  101. #define      CRCCHR    'C'   /* CRC request character */
  102. #define      KCHR    'K'   /* 1K block request character */
  103. #define      BAD_NAME    'u'   /* Bad filename indicator */
  104. /*   CRC-16 constants.  From Usenet contribution by Mark G. Mendel, 
  105.      Network Systems Corp.  (ihnp4!umn-cs!hyper!mark)
  106. */
  107. #define    P    0x1021        /* the CRC polynomial. */
  108. #define W    16            /* number of bits in CRC */
  109. #define B    8            /* the number of bits per char */
  110.  
  111.  
  112. static unsigned char *buff = (u_char *)XFerBuffer;    /* buffer for data */
  113. static char xtbuf[80];        /* xmodem tmp buf to build error msg    */
  114. static int nbchr;        /* number of chars read so far for buffered read */
  115. static long xfilelength;    /* length specified in YMODEM header */
  116. static long fileread;        /* characters actually read so far in file */
  117. static char filename[256];    /* place to construct filenames */
  118. static char recFileName[256];    /* receive file name            */
  119. static char localFile[MAX_FILE_NAME] = DEFAULT_XMODEM_FILENAME;
  120.  
  121. /* option flags and state variables */
  122. static int    CRCMODE;    /* CRC or checksums? */
  123. static int    LONGPACK;     /* do not use long packets on transmit? */
  124. static int    CHECKLENGTH;    /* Are we truncating a file to a YMODEM length? */
  125. static char    *xfileList;
  126. static char    *xfilnam;
  127. static jmp_buf    xjmpbuf;
  128. static int     fd;         /* file descriptor for file being transmitted */
  129. static int     realProtocol;    /* real protocol for automatic detection */
  130. static u_char    paritySave;    /* save old parith, char length        */
  131. static int     oldMode;        /* mode of caller                    */
  132. static long LZERO = 0L;
  133.  
  134. /*   CRC-16 constant array...
  135.      from Usenet contribution by Mark G. Mendel, Network Systems Corp.
  136.      (ihnp4!umn-cs!hyper!mark)
  137. */
  138. /* crctab as calculated by initcrctab() */
  139. static unsigned short crctab[1<<B] = { 
  140.     0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
  141.     0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
  142.     0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
  143.     0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
  144.     0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
  145.     0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
  146.     0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
  147.     0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
  148.     0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
  149.     0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
  150.     0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
  151.     0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
  152.     0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
  153.     0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
  154.     0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
  155.     0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
  156.     0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
  157.     0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
  158.     0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
  159.     0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
  160.     0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
  161.     0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
  162.     0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
  163.     0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
  164.     0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
  165.     0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
  166.     0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
  167.     0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
  168.     0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
  169.     0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
  170.     0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
  171.     0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
  172.    };
  173.  
  174. /*
  175. ** prototypes
  176.  */
  177.  
  178. int xinit2(char *);
  179. void xend(char *, int);
  180. void xexit(void);
  181. void xsfile(char *);
  182. void showProtocol(void);
  183. void xAbortCheck(void);
  184. int xrfile(char *);
  185. int receiveData(int, int, char*);
  186. int receiveFileName(int, int, char *);
  187. void unixify(char *);
  188. char *cpmify(char *);
  189. char *sectdisp(long, int, int);
  190. int getbyte(int, char *);
  191. int readbyte(int seconds);
  192. int readbuf(int, int, int, int *, int *);
  193.  
  194.  
  195. #define sendbyte(data)    rowOutPort(data & cMask)
  196. #define writebuf(buffer,nbytes) rowOutPortBuffer(buffer, nbytes)
  197. #define xalarm(n)        (kermitTimer = n * TICK_SEC)
  198.  
  199.  
  200.  
  201.  
  202.  
  203. void xinit()
  204. {
  205.     /* initialize option flags */
  206.  
  207.     xmodemMode = XY_YMODEM;
  208.     xmodemType = XMODEM_BINARY;
  209.     xmodemLongP = XMODEM_1024;
  210. }
  211.  
  212. static int xinit2(msg)
  213. char *msg;
  214. {
  215.     oldMode = mode;
  216.     mode = M_SETUP;
  217.     if (oldMode == M_COMM)
  218.         showPage1();
  219.  
  220.     if (*msg && (emacs(msg, localFile, MAX_FILE_NAME, (E_HELP|E_FILE)) == ERR 
  221.             || localFile[0] == '\0')) {
  222.         if (oldMode == M_COMM)
  223.             showPage0();
  224.         mode = oldMode;
  225.         return(NO);
  226.     }
  227.  
  228.     downLoading = YES;
  229.     fd = 0;
  230.     xferPanel("XMODEM");
  231.     paritySave = paritybit;
  232.     if (paritybit != NO_PAR_8) {
  233.         paritybit = NO_PAR_8;
  234.         parity = parcalc(paritybit, stopbit);
  235.         initPortDevice(baud, parity);
  236.         putStatus("hterm sets 8 bit, no parity.");
  237.     }
  238.     return(YES);
  239. }
  240.  
  241. static void xend(msg, status)
  242. char *msg;
  243. int status;
  244. {
  245.     downLoading = NO;
  246.     if (fd)
  247.         close(fd);
  248.     bell();
  249.     if (paritySave != paritybit) {
  250.         paritybit = paritySave;
  251.         parity = parcalc(paritybit, stopbit);
  252.         initPortDevice(baud, parity);
  253.     }
  254.     if (oldMode == M_COMM) {
  255.         showPage0();
  256.         putComment(msg, (status == FALSE) ? " failed" : "done");
  257.     }
  258.     mode = oldMode;
  259. }
  260.  
  261. static void xexit()
  262. {
  263.     longjmp(xjmpbuf, 1);
  264. }
  265.  
  266. void xrec()
  267. /*
  268.  * receive xmodem files
  269.  */
  270. {
  271.     int status;
  272.  
  273.     (void)xinit2("");
  274.     strcpy(recFileName, "xmodem.in");
  275.     if (!setjmp(xjmpbuf)) {
  276.         while (xrfile(recFileName) != FALSE)
  277.             ;
  278.         flushInputBuffer();
  279.         status = TRUE;
  280.     } else {
  281.         xprintMsg(X_STATUS, "Abort", LZERO);
  282.         status = FALSE;
  283.     }
  284.     xend("rec", status);
  285. }
  286.  
  287. void xsend()
  288. /*
  289.  * send xmodem files
  290.  */
  291. {
  292.     int first = YES;
  293.     int status;
  294.     char buf[MAX_FILE_NAME+20];    
  295.  
  296.     if (xinit2("X/YMODEM send files: ") == NO)
  297.         return;
  298.  
  299.     xfileList = localFile;
  300.     if (!setjmp(xjmpbuf)) {
  301.         realProtocol = xmodemMode;
  302.         if (getNextFileName(1, &xfileList, &xfilnam, NO) == YES) {
  303.             do {
  304.                 if (first == NO  && realProtocol == XY_XMODEM) {
  305.                     xprintMsg(X_ERROR, "XMODEM can't send multiple files", LZERO);
  306.                     status = FALSE;
  307.                     break;
  308.                 }
  309.                 xsfile(xfilnam);
  310.                 status = TRUE;
  311.                 first = NO;
  312.             } while (getNextFileName(0, &xfileList, &xfilnam, NO) == YES);
  313.         } else {
  314.             sprintf(buf, "%s not found", localFile);
  315.             xprintMsg(X_ERROR, buf, LZERO);
  316.             bell();
  317.         }
  318.         /*
  319.          * terminate remote xmodem; this must be here even if hterm failes to
  320.          * open first file.
  321.          */
  322.         if (realProtocol == XY_YMODEM) {
  323.             xsfile("");
  324.         }
  325.     } else {
  326.         xprintMsg(X_STATUS, "Abort", LZERO);
  327.         bell();
  328.         status = FALSE;
  329.     }
  330.     xend("send", status);
  331. }
  332.  
  333. /*
  334. ** static void xsfile(char *name)
  335.  *
  336.  * x/ymodem file receive.
  337.  * protocol and options are detected automatically.
  338.  *
  339.  * If "name" is NULL; close out the BATCH send.
  340.  */
  341. static void xsfile(name)
  342. char *name;
  343. {
  344.     char *sectdisp();
  345.     char *cpmify();
  346.  
  347.     register int bufctr,         /* array index for data buffer */
  348.     sectnum;            /* packet number for packet header */
  349.  
  350.     register unsigned short checksum;     /* checksum/crc */
  351.  
  352.     static char blockbuf[BBUFSIZ+6];    /* holds packet as it is constructed */
  353.  
  354.     struct stat filestatbuf;    /* file status info */
  355.  
  356.     int attempts,        /* number of attempts made to transmit a packet */
  357.     sendfin,         /* flag that we are sending the last packet */
  358.     closeout,        /* flag that we are closing out batch send */
  359.     filepack,        /* TRUE when sending first packet */
  360.     buf1024,        /* TRUE when sending 1K packets */
  361.     bbufcnt,        /* array index for packet */
  362.     firstchar,        /* first character in protocol transaction */
  363.     bufsize,        /* packet size (128 or 1024) */
  364.     sendresp;          /* response char to sent block received from remote*/
  365.     long sentsect;        /* count of 128 byte sectors actually sent */
  366.     long expsect;        /* count of 128 byte sectors expected to be sent */
  367.     time_t start;        /* starting time of transfer */
  368.     char c, *p;
  369.  
  370.     nbchr = 0;  /* clear buffered read char count */
  371.  
  372.     CRCMODE = FALSE;    /* Receiver determines use of crc or checksum */
  373.  
  374.     buf1024 = xmodemLongP;    /* set packet size flag to command line switch */
  375.  
  376.     closeout = FALSE; filepack = FALSE;    /* indicate state of batch transfer */
  377.  
  378.     showProtocol();
  379.     /* Check on NULL file name */
  380.     if (strcmp(name,"") == 0) {
  381.         if (realProtocol == XY_YMODEM)
  382.             closeout = TRUE;
  383.         else {
  384.             sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  385.             xprintMsg(X_ERROR, "NULL file name in send", LZERO);
  386.             xexit();
  387.         }
  388.     }
  389.  
  390.     if (!closeout) {        /* Are we closing down batch? */
  391.                     /* no; let's send a file */
  392.         if ((fd = open(name, (O_RDONLY|O_BINARY))) < 0) {
  393.             sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  394.             sprintf(xtbuf, msg_cantOpen, name);
  395.             xprintMsg(X_ERROR, xtbuf, LZERO);
  396.             xexit();
  397.         }
  398.  
  399.         stat(name, &filestatbuf);  /* get file status bytes */
  400.         expsect = (filestatbuf.st_size/128) + 1;
  401.         xprintMsg(X_FILENAME, name, LZERO);
  402.         xprintMsg(X_STATUS, "Sending", LZERO);
  403.     }
  404.     /* else Closing down Batch Transmission */
  405.  
  406.     bufsize = buf1024 ? 1024 : 128;        /* set sector size */
  407.  
  408.     sendfin = FALSE;
  409.       attempts = 0;
  410.  
  411.     /* wait for and read startup character */
  412.     do {
  413.         xprintMsg(X_PSENT, NULL, 0L);
  414.         xprintMsg(X_KBYTES, NULL, 0L);
  415.         xprintMsg(X_PERCENT, NULL, 0L);
  416.         xprintMsg(X_RATE, NULL, 0L);
  417.         while (((firstchar = readbyte(1)) != NAK) && 
  418.             (firstchar != CRCCHR) && (firstchar != CAN)) {
  419.             xprintMsg(X_RETRY, NULL, (long)(attempts+1));
  420.             if (++attempts > NAKMAX) {
  421.                 xprintMsg(X_ERROR, "Remote System Not Responding", LZERO);
  422.                 xexit();
  423.             }
  424.             xAbortCheck();
  425.         }
  426.  
  427.         if (firstchar == CRCCHR)
  428.             CRCMODE = TRUE;
  429.     } while (firstchar != NAK && firstchar != CRCCHR);
  430.  
  431.     showProtocol();        /* fix CRC mode        */
  432.     xprintMsg(X_PSIZE, NULL, buf1024 ? 1024L : 128L);
  433.  
  434.     sectnum = 1;
  435.  
  436.     /*
  437.      * if YMODEM is chosen by user, try to use YMODEM
  438.      */
  439.     if (realProtocol == XY_YMODEM) {
  440.         sectnum = 0;
  441.         bufsize = 128;
  442.         filepack = TRUE;
  443.     }
  444.     attempts = 0;
  445.     sentsect = 0;
  446.     start = time((time_t *) 0);
  447.     /* outer packet building/sending loop; loop till whole file is sent */
  448.         do {
  449.         if (closeout && realProtocol == XY_YMODEM && sectnum == 1)    /* close out YMODEM */
  450.             return;
  451.  
  452.         /* get set to send YMODEM data packets */
  453.         if (realProtocol == XY_YMODEM && sectnum == 1) {
  454.             bufsize = buf1024 ? 1024 : 128;
  455.             do {        /* establish handshaking again */
  456.                 while (((firstchar=readbyte(2)) != CRCCHR) && (firstchar != NAK) && (firstchar != CAN)) {
  457.                     xprintMsg(X_RETRY, NULL, (long)(attempts+1));
  458.                     if (++attempts > ERRORMAX) {
  459.                         xprintMsg(X_ERROR, "YMODEM protocol botch, C expected", LZERO);
  460.                         xexit();
  461.                     }
  462.                 }
  463.                 if (firstchar == CAN) {
  464.                     xprintMsg(X_ERROR, "aborted by remote", LZERO);
  465.                     xexit();
  466.                 }
  467.                 xAbortCheck();
  468.             } while ((firstchar != CRCCHR) && (firstchar != NAK));
  469.             attempts = 0;
  470.         }
  471.  
  472.         if ((bufsize == 1024) && (attempts > KSWMAX)) {
  473.             xprintMsg(X_STATUS, "128 byte packet due to excessive errors", LZERO);
  474.             bufsize = 128;
  475.         }
  476.         if ((bufsize == 1024) && ((expsect - sentsect) < 8)) {
  477.             xprintMsg(X_STATUS, "128 byte packet for tail end of file", LZERO);
  478.             bufsize = 128;
  479.         }
  480.         xprintMsg(X_PSIZE, NULL, (long)bufsize);
  481.  
  482.     /* data packet */
  483.         if (sectnum > 0) {
  484.             for (bufctr=0; bufctr < bufsize;) {
  485.                 if (getbyte(fd, &c) == EOF) { 
  486.                     sendfin = TRUE;  /* this is the last sector */
  487.                        if (!bufctr)  /* if EOF on sector boundary */
  488.                               break;  /* avoid sending extra sector */
  489.                           buff[bufctr++] = CTRLZ;  /* pad with Ctrl-Z for CP/M EOF (even do for binary files) */
  490.                        continue;
  491.                 }
  492.                 buff[bufctr++] = c;  /* copy the char without change */
  493.             }
  494.                 if (!bufctr)  /* if EOF on sector boundary */
  495.                           break;  /* avoid sending empty sector */
  496.  
  497.     /* YMODEM filename packet */
  498.         } else {
  499.             for (bufctr=0; bufctr<bufsize; bufctr++)  /* zero packet */
  500.                 buff[bufctr]=0;
  501.             if (!closeout) {
  502.                 strcpy((char *)buff, cpmify(name));
  503.                     /* put in file name, length, mode */
  504.                 p = (char *)buff + strlen(name) + 1;
  505.                 sprintf(p, "%lu %lo %o", filestatbuf.st_size, 
  506.                   filestatbuf.st_mtime, filestatbuf.st_mode);
  507.                 buff[bufsize-2]    = (expsect & 0xff);        /* put in KMD kludge information */
  508.                 buff[bufsize-1] = ((expsect >> 8) & 0xff);
  509.             }
  510.         }
  511.     /* build block to be sent */
  512.         bbufcnt = 0;
  513.         blockbuf[bbufcnt++] = (bufsize == 1024) ? STX : SOH;    /* start of packet char */
  514.         blockbuf[bbufcnt++] = sectnum;        /* current sector # */
  515.         blockbuf[bbufcnt++] = ~sectnum;   /* and its complement */
  516.  
  517.         checksum = 0;  /* initialize checksum */
  518.                    for (bufctr=0; bufctr < bufsize; bufctr++) {
  519.             blockbuf[bbufcnt++] = buff[bufctr];
  520.             checksum = CRCMODE ? (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ buff[bufctr]]
  521.                        : ((checksum+buff[bufctr]) & 0xff);
  522.         }
  523.  
  524.         if (CRCMODE) {        /* put in CRC */
  525.             checksum &= 0xffff;
  526.             blockbuf[bbufcnt++] = ((checksum >> 8) & 0xff);
  527.             blockbuf[bbufcnt++] = (checksum & 0xff);
  528.         } else            /* put in checksum */
  529.             blockbuf[bbufcnt++] = checksum;
  530.  
  531.                 attempts = 0;
  532.     /* send a packet */
  533.                 do {                /* inner packet loop */
  534.             flushInputBuffer();                      /* purge anything in input queue */
  535.             writebuf(blockbuf, bbufcnt);    /* write the block */
  536.                     attempts++;
  537.             sendresp = readbyte(10);  /* get response from remote */
  538.  
  539.             if (sendresp != ACK) {
  540.                 xprintMsg(X_RETRY, NULL, (long)attempts);
  541.                 if (sendresp == TIMEOUT)
  542.                     sprintf(xtbuf, "Timeout on sector %s",sectdisp(sentsect,bufsize,1));
  543.                 else if (sendresp == NAK)
  544.                        sprintf(xtbuf, "NAK on sector %s",sectdisp(sentsect,bufsize,1));
  545.                 else
  546.                        sprintf(xtbuf, "Non-ACK on sector %s",sectdisp(sentsect,bufsize,1));
  547.                    xprintMsg(X_STATUS, xtbuf, LZERO);
  548.                 /*
  549.                  * switch YMODEM to XMODEM
  550.                  */
  551.                 if (attempts > Y_TO_X_SW && sectnum == 0) {
  552.                     attempts = 0;
  553.                     realProtocol = XY_XMODEM;
  554.                     showProtocol();
  555.                     xprintMsg(X_STATUS, "receiver may be XMODEM", LZERO);
  556.                     break;
  557.                 }
  558.             }
  559.         } while((sendresp != ACK) && (attempts < ERRORMAX));    /* close of inner loop */
  560.  
  561.     /* prepare next sector */
  562.                sectnum++;  /* increment to next sector number */
  563.         if (!filepack)
  564.             sentsect += (bufsize == 128) ? 1 : 8;
  565.         filepack = FALSE;
  566.         if (!closeout) {
  567.             time_t    ptime = time((time_t *)0) - start;
  568.  
  569.             xprintMsg(X_PSENT, NULL, (bufsize == 128) ? sentsect : sentsect/8L);
  570.             xprintMsg(X_KBYTES, NULL, sentsect/8L);
  571.             if (expsect)
  572.                 xprintMsg(X_PERCENT, NULL, (long)((long)sentsect  * 100L / expsect));
  573.             if (ptime) {
  574.                 xprintMsg(X_RATE, NULL, (long)((long)sentsect * 128 / ptime));
  575.             }
  576.             xprintMsg(X_RETRY, NULL, (long)attempts);
  577.         }
  578.     } while (!sendfin && (attempts < ERRORMAX));    /* end of outer loop */
  579.  
  580.  
  581.     /* error processing */
  582.     if (attempts >= ERRORMAX) {
  583.         sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  584.         xprintMsg(X_ERROR, "Too many errors in transmission", LZERO);
  585.         xexit();
  586.     }
  587.  
  588.         attempts = 0;
  589.         sendbyte(EOT);  /* send 1st EOT to close down transfer */
  590.     
  591.         while ((readbyte(15) != ACK) && (attempts++ < EOTMAX)) { /* wait for ACK of EOT */
  592.         xprintMsg(X_RETRY, NULL, (long)attempts);
  593.            sendbyte(EOT);
  594.     }
  595.         if (attempts >= RETRYMAX) {
  596.            xprintMsg(X_ERROR, "Remote System Not Responding on Completion", LZERO);
  597.         xexit();
  598.     }
  599.  
  600.         close(fd);
  601.     fd = 0;
  602.         xprintMsg(X_STATUS, "Send Complete", LZERO);
  603. }
  604.  
  605. static void showProtocol()
  606. {
  607.     char *p;
  608.  
  609.     if (realProtocol == XY_YMODEM)
  610.         p = "YMODEM Batch";
  611.     else
  612.         p = "XMODEM";
  613.     sprintf(xtbuf, "%s (%s)", p, CRCMODE ? "CRC" : "Checksum");
  614.     xprintMsg(X_PROTOCOL, xtbuf, LZERO);
  615. }
  616.  
  617. static void xAbortCheck()
  618. {
  619.     short uk;
  620.  
  621.     if ((uk = keyin()) != -1 && uk == ESC) {
  622.         xprintMsg(X_ERROR, "Aborted by user", LZERO);
  623.         xexit();
  624.     }
  625. }
  626.  
  627. /* This routine is one HUGE do-while loop with far to many indented levels.
  628.  * I chose this route to facilitate error processing and to avoid GOTOs.
  629.  * Given the troubles I've had keeping the nested IF statements straight,
  630.  * I was probably mistaken... 
  631.  * 
  632.  * OF COURSE YES! YOU ARE CRAZY! I WILL BREAK IT DOWN!
  633.  */
  634.  
  635. static int sectnum;    /* number of last received packet (modulo 128) */
  636. static int errorflag;  /* set true when packet (or first char of putative packet) is invalid */
  637. static int fatalerror; /* set within main "read-packet" Do-While when bad error found */
  638. static long expsect;    /* expected number of sectors (YMODEM batch) */
  639. static int firstwait;  /* seconds to wait for first character in a packet */
  640. static long recvsectcnt;   /* running sector count (128 byte sectors) */
  641. static long modtime;       /* Unix style file mod time from YMODEM header */
  642. static time_t start;       /* starting time of transfer */
  643. static int openflag;    /* is file open for writing? */
  644. static int endFlag;
  645. extern char *sectdisp();
  646.  
  647. static int xrfile(name)
  648. /*
  649.  * receive a file
  650.  * returns TRUE if in the midst of a batch transfer
  651.  * returns FALSE if no more files are coming
  652.  */
  653. char *name;
  654. {
  655.  
  656.     int firstchar,  /* first character of a packet */
  657.     sectcurr,   /* second byte of packet--should be packet number (mod 128) */
  658.     sectcomp,   /* third byte of packet--should be complement of sectcurr */
  659.     errors,     /* count of errors for each packet */
  660.     sterrors,   /* count of errors during startup handshake */
  661.     bufsize;    /* packet size (128 or 1024) */
  662. #ifdef COMP_MSC
  663.     time_t timep[2];    /* used in setting mod time of received file */
  664. #endif
  665.     int status;
  666.  
  667.     fatalerror = FALSE;
  668.     firstwait = WAITFIRST;  /* For first packet, wait short time */
  669.     sectnum = 0;
  670.     errors = 0;
  671.     recvsectcnt = 0;
  672.     bufsize = 128;
  673.     modtime = 0l; 
  674.     xfilelength = 0l; fileread =0l; CHECKLENGTH = FALSE;
  675.     openflag = FALSE;
  676.  
  677.     /* start up transfer */
  678.  
  679.     sterrors = 0;
  680.     flushInputBuffer();         /* flush input queue */
  681.  
  682.     /*
  683.      * first assume XMODEM
  684.      */
  685.     realProtocol = XY_XMODEM;
  686.     LONGPACK = xmodemLongP == XMODEM_1024 ? 1 : 0;
  687.  
  688.     /*
  689.      * first try CRC-mode
  690.      */
  691.     CRCMODE = TRUE;
  692.     sendbyte(CRCCHR);
  693.  
  694.     endFlag = FALSE;
  695.     while (endFlag == FALSE && fatalerror == FALSE) {
  696.         xprintMsg(X_STATUS, "Receiving", LZERO);
  697.         errorflag = FALSE;
  698.         do {             /* start by reading first byte in packet */
  699.             firstchar = readbyte(firstwait);
  700.         } while ((firstchar != SOH)
  701.             && (firstchar != STX) 
  702.             && (firstchar != EOT) 
  703.             && (firstchar != ACK || recvsectcnt > 0) 
  704.             && (firstchar != TIMEOUT) 
  705.             && (firstchar != CAN || recvsectcnt > 0));
  706.  
  707.         switch (firstchar) {
  708.         case EOT:          /* check for REAL EOT */
  709.             if (realProtocol == XY_XMODEM) {
  710.                 /*
  711.                  * XMODEM on some BBS can not handle NAK for EOT!
  712.                  */
  713.                 endFlag = TRUE;
  714.             } else {
  715.                 flushInputBuffer();
  716.                 sendbyte(NAK);              /* NAK the EOT */
  717.                 if ((firstchar = readbyte(3)) == EOT) {   /* check next character */
  718.                     endFlag = TRUE;
  719.                 } else {
  720.                     xprintMsg(X_STATUS, "Spurious EOT detected; ignored", LZERO);
  721.                     if ((firstchar == SOH) || (firstchar == STX) ||
  722.                         (firstchar == ACK && recvsectcnt == 0) ||
  723.                         (firstchar == CAN && recvsectcnt == 0) ||
  724.                         (firstchar == TIMEOUT))
  725.                         endFlag = TRUE;
  726.                     else {
  727.                         firstchar = 0;
  728.                         errorflag = TRUE;
  729.                     }
  730.                 }
  731.             }
  732.             break;
  733.         case TIMEOUT:
  734.             if (recvsectcnt > 0) {
  735.                 sprintf(xtbuf, "Timeout on Sector %s", sectdisp(recvsectcnt,bufsize,1));
  736.                 xprintMsg(X_STATUS, xtbuf, LZERO);
  737.             }
  738.             errorflag = TRUE;
  739.             break;
  740.     /* start reading packet */
  741.         case SOH:
  742.         case STX:
  743.             bufsize = (firstchar == SOH) ? 128 : 1024;
  744.             if (recvsectcnt == 0) {          /* 1st data packet, initialize */
  745.                 xprintMsg(X_PSIZE, NULL, (long)bufsize);
  746.                 start = time((time_t *) 0);
  747.                 errors = 0;
  748.                 firstwait = 5;
  749.             }
  750.             sectcurr = readbyte(3);
  751.             sectcomp = readbyte(3);
  752.             /* is packet number checksum correct? */
  753.             if ((sectcurr + sectcomp) != 0xff) {
  754.                 /* bad packet number checksum */
  755.                 sprintf(xtbuf, "Header Sector Number Error on Sector %s\n", sectdisp(recvsectcnt, bufsize,1));
  756.                 xprintMsg(X_STATUS, xtbuf, LZERO);
  757.                 errorflag = TRUE;
  758.                 break;
  759.             }
  760.             if (sectcurr == ((sectnum+1) & 0xff))  /* is packet number correct? */
  761.                 status = receiveData(sectcurr, bufsize, name);
  762.             else
  763.                 status  = receiveFileName(sectcurr, bufsize, name);
  764.             if (status == FALSE)
  765.                 return(FALSE);
  766.             break;
  767.         }
  768.     /* error correction */
  769.         /* handle startup handshake */
  770.         if (recvsectcnt == 0 && errorflag && firstchar != EOT) { 
  771.             xprintMsg(X_RETRY, NULL, (long)sterrors);
  772.             if (++sterrors >= STERRORMAX)
  773.                 fatalerror = TRUE;
  774.             else if (sterrors == CRCSWMAX) {
  775.                 if (CRCMODE) {
  776.                     CRCMODE = FALSE;
  777.                     xprintMsg(X_STATUS, "Sender not accepting CRC, use checksum", LZERO);
  778.                     sendbyte(NAK);
  779.                 } else {
  780.                     CRCMODE = TRUE;
  781.                     xprintMsg(X_STATUS, "Sender not accepting checksum, use CRC", LZERO);
  782.                     sendbyte(CRCCHR);
  783.                 }
  784.             } else if (CRCMODE)
  785.                 sendbyte(CRCCHR);
  786.             else
  787.                 sendbyte(NAK);
  788.         }
  789.         if (errorflag && !fatalerror && recvsectcnt != 0) {   /* Handle errors */
  790.             xprintMsg(X_RETRY, NULL, (long)errors);
  791.             if (++errors >= ERRORMAX)
  792.                 fatalerror = TRUE;
  793.             else {                       /* flush input and NAK the packet */
  794.                 flushInputBuffer();
  795.                 while (readbyte(1) != TIMEOUT)  /* wait for line to settle */
  796.                     ;
  797.                 sendbyte(NAK);
  798.             }
  799.         }
  800.  
  801.     }
  802.  
  803.     if ((firstchar == EOT) && !fatalerror) { /* normal exit? */
  804.         if (openflag)       /* close the file */
  805.             close(fd);
  806.         sendbyte(ACK);      /* ACK the EOT */
  807.         xprintMsg(X_STATUS, "Receive Complete", LZERO);
  808.  
  809. #ifdef COMP_MSC
  810.         if (openflag && modtime) {  /* set file modification time */
  811.             timep[0] = time((time_t *) 0);
  812.             timep[1] = modtime;
  813.             utime(name, timep);
  814.         }
  815. #endif /* COMP_MSC */    /* ignore is TurboC ?? */
  816.         
  817.         /*
  818.          * return from protocol. if YMODEM, we shall return.
  819.          */
  820.         if (realProtocol == XY_YMODEM)
  821.             return(TRUE);
  822.         else
  823.             return(FALSE);
  824.     }
  825.     /* no, error exit */
  826.     if (openflag) {
  827.         sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  828.         close(fd);
  829. #if 0
  830.         unlink(name);
  831. #endif
  832.         xprintMsg(X_ERROR, "Too many error! deleting file", LZERO);
  833.     } else if (recvsectcnt == 0)
  834.         xprintMsg(X_ERROR, "Remote system is not responding", LZERO);
  835.     else
  836.         xprintMsg(X_ERROR, "Too many errors", LZERO);
  837.     return(FALSE);
  838. }
  839.  
  840. static int receiveData(sectcurr, bufsize, name)
  841. int sectcurr;
  842. int bufsize;
  843. char *name;
  844. /*
  845.  * receive data packet or file name packet
  846.  */
  847. {
  848.     int checksum;   /* packet checksum */
  849.     int inchecksum; /* incoming checksum or CRC */
  850.     int    rate;
  851.     time_t    ptime;
  852.     long readbackup;    /* "backup" value for characters read in file */    
  853.     int bufctr; /* number of real chars in read packet */
  854.  
  855.     /* Read, process and calculate checksum for a buffer of data */
  856.     readbackup = fileread;
  857.     if (readbuf(bufsize, 5, (xmodemType == XMODEM_TEXT), &checksum, &bufctr) == TIMEOUT) {
  858.         sprintf(xtbuf, "Timeout while reading sector %s\n",sectdisp(recvsectcnt,bufsize,1));
  859.         xprintMsg(X_STATUS, xtbuf, LZERO);
  860.         fileread = readbackup;
  861.         errorflag = TRUE;
  862.         return(TRUE);
  863.     }
  864.     if (sectcurr == 1 && realProtocol == XY_XMODEM) /* if first data packet */
  865.         showProtocol();
  866.     /* verify checksum or CRC */
  867.     if (CRCMODE) {
  868.         checksum &= 0xffff;
  869.         inchecksum = readbyte(3);      /* get 16-bit CRC */
  870.         inchecksum = (inchecksum<<8) | readbyte(3);
  871.     } else
  872.         inchecksum = readbyte(3);      /* get simple 8-bit checksum */
  873.     if (inchecksum != checksum) {        /* check sum error    */
  874.         sprintf(xtbuf, "Checksum Error on Sector %s:  sent=%x  recvd=%x", sectdisp(recvsectcnt,bufsize,1), inchecksum, checksum);
  875.         xprintMsg(X_STATUS, xtbuf, LZERO);
  876.         fileread = readbackup;
  877.         errorflag = TRUE;
  878.         return(TRUE);
  879.     }
  880.     /*
  881.      * check sum OK, let's go!
  882.      */
  883.     recvsectcnt += (bufsize == 128) ? 1L : 8L;
  884.     sectnum = sectcurr; 
  885.     xprintMsg(X_PRECV, NULL, (bufsize == 128) ? recvsectcnt : (recvsectcnt / 8L));
  886.     xprintMsg(X_KBYTES, NULL, (recvsectcnt / 8L));
  887.     if ((ptime = time((time_t *)0) - start) == 0) {
  888.         rate = 0;
  889.     } else {
  890.         rate = (int)((long)recvsectcnt * 128L / ptime);
  891.     }
  892.     xprintMsg(X_RATE, NULL, (long)rate);
  893.     if (realProtocol == XY_YMODEM && expsect) {
  894.         xprintMsg(X_PERCENT, NULL, (long)((long)recvsectcnt * 100L / expsect));
  895.     }
  896.  
  897.     if (!openflag) {     /* open output file if necessary */
  898.         openflag = TRUE;
  899.         if ((fd = open(name, O_WRONLY|O_BINARY|O_CREAT, 0644)) < 0) {
  900.             sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  901.             xprintMsg(X_ERROR, msg_cantOpen, LZERO);
  902.             return(FALSE);
  903.         }
  904.         if (realProtocol == XY_XMODEM)
  905.             xprintMsg(X_FILENAME, name, LZERO);
  906.     }
  907.     if (write(fd, (char *) buff, bufctr) != bufctr) {
  908.         close(fd);
  909.         unlink(name);
  910.         xprintMsg(X_ERROR, "File Write Error", LZERO);
  911.         return(FALSE);
  912.     } else {
  913.         flushInputBuffer();          /* flush input */
  914.         sendbyte(ACK);      /* ACK the received packet */
  915.     }
  916.     return(TRUE);
  917. }
  918.  
  919. static receiveFileName(sectcurr, bufsize, name)
  920. int sectcurr;
  921. int bufsize;
  922. char *name;
  923. /* sector number is wrong OR Ymodem filename */
  924. {
  925.     int checksum;   /* packet checksum */
  926.     int inchecksum; /* incoming checksum or CRC */
  927.     int junk;    /* file mode, buffer counter    */
  928.     char *p;
  929.  
  930.     if (sectcurr == 0 && recvsectcnt == 0) {  /* Ymodem file-name packet */
  931.         /* Read and process a file-name packet */
  932.         if (readbuf(bufsize, 5, FALSE, &checksum, &junk) == TIMEOUT) { 
  933.             xprintMsg(X_STATUS, "Timeout while reading filename packet", LZERO);
  934.             errorflag = TRUE;
  935.             return(TRUE);
  936.         }
  937.         /* verify checksum or CRC */
  938.         if (CRCMODE) {
  939.             checksum &= 0xffff;
  940.             inchecksum = readbyte(3);  /* get 16-bit CRC */
  941.             inchecksum = (inchecksum<<8) | readbyte(3);
  942.         } else
  943.             inchecksum = readbyte(3);  /* get simple 8-bit checksum */
  944.         if (inchecksum != checksum) { /* good checksum, hence good filename */
  945.             xprintMsg(X_STATUS, "checksum error on filename sector", LZERO);
  946.             errorflag = TRUE;
  947.             return(TRUE);
  948.         }
  949.         strcpy(name, (char *)buff);
  950.         /*    expsect = ((buff[bufsize-1]<<8) | buff[bufsize-2]); */
  951.         realProtocol = XY_YMODEM;
  952.         showProtocol();
  953.         if (strlen(name) == 0) {  /* check for no more files */
  954.             flushInputBuffer();          /* flush input */
  955.             sendbyte(ACK);      /* ACK the packet */
  956.             xprintMsg(X_STATUS, "YMODEM Batch Receive Complete", LZERO);
  957.             endFlag = TRUE;
  958.             return (FALSE);
  959.         }
  960.         unixify(name);       /* make filename canonical */
  961.         /* read rest of YMODEM header */
  962.         p = (char *)buff + strlen((char *)buff) + 1;
  963.         sscanf(p, "%ld%lo%o", &xfilelength, &modtime, &junk);
  964.         xprintMsg(X_FILENAME, name, LZERO);
  965.         fileread = 0l;
  966.         expsect = 0L;
  967.         if (xfilelength) {
  968.             CHECKLENGTH = TRUE;
  969.             expsect = xfilelength/128L+1L;
  970.         }
  971.         sendbyte(ACK);      /* ACK the packet */
  972.         firstwait = WAITFIRST;  /* reset to negotiate */
  973.     } else if (sectcurr == sectnum) {  /* duplicate sector? */
  974.         sprintf(xtbuf, "Duplicate sector %s flushed\n", sectdisp(recvsectcnt,bufsize,0));
  975.         xprintMsg(X_STATUS, xtbuf, LZERO);
  976.         flushInputBuffer();                  /* REALLY flush input */
  977.         while(readbyte(1) != TIMEOUT)
  978.             ;
  979.         sendbyte(ACK);
  980.     } else {            /* no, real phase error */
  981.         sprintf(xtbuf, "Phase Error - Expected packet is %s\n", sectdisp(recvsectcnt,bufsize,1));
  982.         xprintMsg(X_STATUS, xtbuf, LZERO);
  983.         errorflag = TRUE;
  984.         fatalerror = TRUE;
  985.     }
  986.     return(TRUE);
  987. }
  988.  
  989.  
  990.  
  991. /*
  992.  *  Various routines for batch transfer
  993.  */
  994.  
  995.  
  996. /* make sure filename sent or received in YMODEM batch is canonical. */
  997.  
  998. /* Incoming: Turn Unix '/' into CP/M ':' and translate to all lower case.
  999.  * Remove trailing dot.
  1000.  */
  1001.  
  1002. static void unixify (name)
  1003. char *name;
  1004. {
  1005.     char *ptr;
  1006.  
  1007.     /* change '/' to ':' and convert to lower case */
  1008.     for (ptr=name; *ptr; ++ptr)
  1009.         {
  1010.         if (*ptr == '/')
  1011.             *ptr = ':';
  1012.         if (isupper (*ptr))
  1013.             *ptr |= 040;
  1014.         }
  1015.  
  1016.     /* remove trailing dot if present */
  1017.     ptr--;
  1018.     if (*ptr == '.')
  1019.         *ptr = '\0';
  1020. }
  1021.  
  1022. /* make sure filename sent or received in YMODEM batch is canonical. */
  1023.  
  1024. /* Outgoing: Turn ':' into '/' (for symmetry!) and turn into all lower case.
  1025.  * Remove everything before last '/'.  Use "filename" to hold final name.
  1026.  */
  1027.  
  1028. static char *
  1029. cpmify (name)
  1030. char *name;
  1031. {
  1032.     char *ptr, *slash;
  1033.  
  1034.     /* find last '/' and copy rest of name */
  1035.  
  1036.     slash = name;
  1037.     for (ptr=name; *ptr; ++ptr)
  1038.         if (*ptr == '/')
  1039.             slash = ptr + 1;
  1040.     strcpy (filename, slash);
  1041.  
  1042.     /* change ':' to '/' and covert to all lower case */
  1043.  
  1044.     for (ptr=filename; *ptr; ++ptr)
  1045.         {
  1046.         if (*ptr == ':')
  1047.             *ptr = '/';
  1048.         if (isupper (*ptr))
  1049.             *ptr |= 040;
  1050.         }
  1051.     return (filename);
  1052. }
  1053. /* Construct a proper (i.e. pretty) sector count for messages */
  1054.  
  1055. static char
  1056. *sectdisp(recvsectcnt, bufsize, plus1)
  1057. long recvsectcnt;
  1058. int bufsize, plus1;
  1059. {
  1060.     static char string[20];
  1061.     if (plus1)
  1062.         recvsectcnt += (bufsize == 128) ? 1 : 8;
  1063.     if (bufsize == 128 || recvsectcnt == 0)
  1064.         sprintf (string, "%d", recvsectcnt);
  1065.     else
  1066.         sprintf (string, "%d-%d", recvsectcnt-7, recvsectcnt);
  1067.     return(string);
  1068. }
  1069.  
  1070. /*
  1071.  *
  1072.  *    Get a byte from the specified file.  Buffer the read so we don't
  1073.  *    have to use a system call for each character.
  1074.  *
  1075.  */
  1076. static int getbyte(fildes, ch)                /* Buffered disk read */
  1077. int fildes;
  1078. char *ch;
  1079.  
  1080.     {
  1081.     static char buf[BUFSIZ];    /* Remember buffer */
  1082.     static char *bufp = buf;    /* Remember where we are in buffer */
  1083.     
  1084.     if (nbchr == 0)            /* Buffer exausted; read some more */
  1085.     {
  1086.         if ((nbchr = read(fildes, buf, BUFSIZ)) < 0) {
  1087.             xprintMsg(X_ERROR, "File Read Error", LZERO);
  1088.         }
  1089.         bufp = buf;        /* Set pointer to start of array */
  1090.     }
  1091.     if (--nbchr >= 0)
  1092.     {
  1093.         *ch = *bufp++;
  1094.         return(0);
  1095.     } else {
  1096.         return(EOF);
  1097.     }
  1098. }
  1099.  
  1100.  
  1101.  
  1102. /*
  1103.  * basic I/O
  1104.  */
  1105. static readbyte(seconds)
  1106. int    seconds;
  1107. {
  1108.     register int    c;
  1109.  
  1110.     xalarm(seconds);
  1111.     for (;;) {
  1112.         if ((c = getSerial()) != -1) {
  1113.             return (c & 0xff);
  1114.         } else if ((c = keyin()) != -1) {
  1115.             if (c == 0x1b) {        /* ESC    */
  1116.                 sendbyte(CAN);
  1117.                 sendbyte(CAN);
  1118.                 sendbyte(CAN);
  1119.                 xexit();
  1120.             }
  1121.         }
  1122.         if (kermitTimer <= 0) {
  1123.             return(TIMEOUT);        /* time out    */
  1124.         }
  1125.     }
  1126. }
  1127.  
  1128. static int
  1129. readbuf(bufsize, seconds, tmode, checksum, bufctr)
  1130. int bufsize;    /* number of chars to be read */
  1131. int seconds;     /* timeout period for each read */
  1132. int tmode;        /* text mode or not    */
  1133. int *checksum;         /* pointer to checksum value */
  1134. int *bufctr;    /* length of actual data string in buffer */
  1135. {
  1136.     int recfin = FALSE;        /* flag that EOF read */
  1137.     register unsigned char c;    /* character being processed */
  1138.     register int    c1;
  1139.     register unsigned short chksm;    /* working copy of checksum */
  1140.     register int bfctr;    /* working copy of bufctr */
  1141.     register int    bp;    /* current buffer pointer    */
  1142.     char *sectdisp();
  1143.  
  1144.     xalarm(seconds);
  1145.     chksm = 0;
  1146.     bfctr = 0;
  1147.  
  1148.     for (bp = 0; bp < bufsize; ) {
  1149.         if ((c1 = getSerial()) != -1) {
  1150.             xalarm(seconds);        /* reset timer    */
  1151.             bp++;                /* add counter    */
  1152.             c = c1 & 0xff;            /* mask upper byte */
  1153.  
  1154.         /* now process part of packet we just read */
  1155.  
  1156.             buff[bfctr] = c;
  1157.             fileread++;
  1158.  
  1159.             if (CRCMODE) {  /* CRC */
  1160.                 chksm = (chksm<<B) ^ crctab[(chksm>>(W-B)) ^ c];
  1161.             } else  {       /* checksum */
  1162.                 chksm = ((chksm+c) & 0xff);
  1163.             }
  1164.             if (CHECKLENGTH && fileread > xfilelength) {    /* past EOF ? */
  1165.                 continue;
  1166.             }
  1167.  
  1168.             if (tmode) {            /* text mode processing */
  1169.                 if (c == CR || c == 0)    /* skip CRs and nulls */
  1170.                     continue;
  1171.                 else if (c == CTRLZ) {    /* CP/M EOF char */
  1172.                     recfin = TRUE;
  1173.                     continue;
  1174.                 } else if (!recfin)    /* don't increment if past EOF */
  1175.                     bfctr++;
  1176.             } else {    /* binary */
  1177.                 bfctr++;
  1178.                  }
  1179.         } else {
  1180.             if ((c = keyin()) != -1) {
  1181.                 if (c == 0x1b) {    /* ESC */
  1182.                     sendbyte(CAN);
  1183.                     sendbyte(CAN);
  1184.                     sendbyte(CAN);
  1185.                     xexit();
  1186.                 }
  1187.             }
  1188.             if (kermitTimer <= 0) {
  1189.                 return (TIMEOUT);
  1190.             }
  1191.         }
  1192.     }
  1193.  
  1194.     *checksum = chksm;
  1195.     *bufctr = bfctr;
  1196.     return(0);
  1197. }
  1198.  
  1199. #endif /* XMODEM */
  1200.