home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / PROTOCOL / JMOD311.ZIP / JMODEM_A.C < prev    next >
Text File  |  1992-02-02  |  40KB  |  610 lines

  1. /****************************************************************************/
  2. /*    FILE JMODEM_A.C                                                       */
  3. /*                                                                          */
  4. /*    The JMODEM protocol            MicroSoft (r)  'C' V6.00               */
  5. /*    Created 03-FEB-1990            Richard B. Johnson                     */
  6. /*                                   405 Broughton Drive                    */
  7. /*                                   Beverly, Massachusetts 01915           */
  8. /*                                   BBS (508) 922-3166                     */
  9. /*                                                                          */
  10. /*    An external protocol for high-speed data transmission.                */
  11. /*                                                                          */
  12. /*    This is the MAIN module                                               */
  13. /*    The required modules are:                                             */
  14. /*    JMODEM.H    (function prototypes and structures)                      */
  15. /*    UART.H      (8250 UART parameters)                                    */
  16. /*    SCREEN.H    (function protypes and structures for the screen)         */
  17. /*    JMODEM_A.C   (this module)                                            */
  18. /*    JMODEM_B.C   (memory allocation and input parsing)                    */
  19. /*    JMODEM_C.C   (all file I/O)                                           */
  20. /*    JMODEM_D.C   (encode/decode and CRC routines)                         */
  21. /*    JMODEM_E.C   (communications I/O routines)                            */
  22. /*    JMODEM_F.C   (the screen I/O routines)                                */
  23. /*    JMODEM_G.ASM (Interrupt service routines after V3.10)                 */
  24. /*    JMODEM.      (The MAKE file )                                         */
  25. /*                                                                          */
  26. /*    This program requires about 67k of free RAM to execute properly.      */
  27. /*    If you have 66k or less, it will execute, but the screens will        */
  28. /*    not be written or replaced properly. If you have only 64k, the        */
  29. /*    program will exit with an error message.                              */
  30. /*                                                                          */
  31. /*    Revision History:                                                     */
  32. /*    V3.00   Beta test                  11-FEB-1990   Richard B. Johnson   */
  33. /*    V3.01   First release              18-FEB-1990   Richard B. Johnson   */
  34. /*    V3.02   Revised                    19-FEB-1990   Richard B. Johnson   */
  35. /*                                                                          */
  36. /*      (1)   A bug in MicroSoft _calloc()  allocates overlapping           */
  37. /*            buffers so data files were getting corrupted. I had           */
  38. /*            used both _calloc() and _malloc() at the same time and        */
  39. /*            they didn't like it. I changed the memory allocation          */
  40. /*            to _malloc() only and it seems to work okay.                  */
  41. /*                                                                          */
  42. /*      (2)   While debugging, I found some structures I didn't need and    */
  43. /*            removed them. Changed some code to accommodate.               */
  44. /*                                                                          */
  45. /*      (3)   Added a file-size during downloads.                           */
  46. /*                                                                          */
  47. /*      (4)   Changed code in the data encoding (compression) routine       */
  48. /*            in an attempt to speed it up.                                 */
  49. /*                                                                          */
  50. /*    V3.03   Revised                   20-FEB-1990  Richard B. Johnson     */
  51. /*                                                                          */
  52. /*      (5)   Fixed bug in compression routine where the loop wasn't        */
  53. /*            terminating properly, adding random characters. Bug was       */
  54. /*            created during V3.02 change.                                  */
  55. /*                                                                          */
  56. /*    V3.04   Revised                   27-FEB-1990  Richard B. Johnson     */
  57. /*                                                                          */
  58. /*      (1)   Modified the block-size routine and the receive-block         */
  59. /*            routine in an attempt to improve the noise immunity.          */
  60. /*            Does not abort even if you whistle into the telephone         */
  61. /*            during uploads and downloads. Waits 5 seconds to clear        */
  62. /*            the interrupt buffer when a bad block-size is received.       */
  63. /*                                                                          */
  64. /*      (2)   Added a 1/2 second wait for modem status when opening         */
  65. /*            channel. This might accommodate slow modems response to       */
  66. /*            RTS.                                                          */
  67. /*                                                                          */
  68. /*    V3.05   Revised                   22-MAR-1990  Richard B. Johnson     */
  69. /*                                                                          */
  70. /*      (1)   Removed _sprintf() runtime library calls to shorten           */
  71. /*            the code. Saved about 4k.                                     */
  72. /*                                                                          */
  73. /*      (2)   Removed extra spaces in the signon-logo to shorten            */
  74. /*            the program size.                                             */
  75. /*                                                                          */
  76. /*      (3)   Changed the method of creating a fixed-length string          */
  77. /*            for both the block size and cps numbers which saved about     */
  78. /*            800 bytes of program size.                                    */
  79. /*                                                                          */
  80. /*      (4)   Changed numerous array indexes in JMODEM_F.C to pointers      */
  81. /*            to reduce code size. Saved a few hundred bytes and should     */
  82. /*            improve speed of screen output.                               */
  83. /*                                                                          */
  84. /*      (5)   Created a local _puts() routine which saved over 6k from the  */
  85. /*            MicroSoft C runtime library version. (JMODEM_F.C)             */
  86. /*                                                                          */
  87. /*    V3.06   Revised                   07-APR-1990  Richard B. Johnson     */
  88. /*                                                                          */
  89. /*      (1)   Put the filename text into the syst structure as a pointer    */
  90. /*            to char. This allowed me to save 56 bytes of code and now     */
  91. /*            only two parameters are passed to the _screen() function.     */
  92. /*                                                                          */
  93. /*      (2)   Modified the syst structure and supporting code.              */
  94. /*                                                                          */
  95. /*      (3)   Moved all external data and functions to the JMODEM.H file.   */
  96. /*                                                                          */
  97. /*      (4)   Moved _disp() "usage" module to JMODEM_F.C                    */
  98. /*                                                                          */
  99. /*      (5)   Changed arrays in JMODEM_B.C to pointers to reduce code-      */
  100. /*            size. Eliminated _strcpy() from the command-line parsing      */
  101. /*            routines. Brought the code-size to less than 12,000 bytes.    */
  102. /*                                                                          */
  103. /*      (6)   Reduced the code-size in the _encode(), _decode(), and        */
  104. /*            _crc() routines in JMODEM_D.C. Removed shifts to improve      */
  105. /*            speed and replaced the shifts with pointers for altering      */
  106. /*            portions of the strings.                                      */
  107. /*                                                                          */
  108. /*      (7)   Made a _cancel() routine in JMODEM_A.C to send ^Xes upon      */
  109. /*            abort.                                                        */
  110. /*                                                                          */
  111. /*      (8)   Removed the bit being set "OUT 1" via the modem-control       */
  112. /*            register in the "open" routine in JMODEM_E.C. This was        */
  113. /*            causing some internal modems to lock up as they use this      */
  114. /*            bit for something. "OUT 2" is used to enable IRQ on most      */
  115. /*            clone RS-232 boards and modems. The Heathkit HZ-100 boards    */
  116. /*            will probably not work anymore because they use "OUT 1".      */
  117. /*                                                                          */
  118. /*                                                                          */
  119. /*    V3.07   Revised                   03-MAY-1990  Richard B. Johnson     */
  120. /*                                                                          */
  121. /*      (1)   Rewrote code to remove the requirement for a file buffer.     */
  122. /*            This means that this buffer does not need to be allocated,    */
  123. /*            saving about 8k of RAM at run-time.  ( JMODEM_A.C )           */
  124. /*                                                                          */
  125. /*            Program now only requires 52k of free RAM to execute okay.    */
  126. /*                                                                          */
  127. /*      (2)   Changed the header file, JMODEM.H, and function calling       */
  128. /*            procedures to file_io() and screen() to allow variable-       */
  129. /*            length parameter-lists. This eliminates the requirement       */
  130. /*            to pass a NULL as a place-holder on procedures that don't     */
  131. /*            always require all possible parameters to be passed. This     */
  132. /*            saved about 50 bytes of code.                                 */
  133. /*                                                                          */
  134. /*      (3)   Changed the "Usage" prompt and code to reduce program size.   */
  135. /*            Saved about 60 bytes.                                         */
  136. /*                                                                          */
  137. /*      (4)   Changed keyboard break interrupt in JMODEM_E.C so it sets     */
  138. /*            the global timer to zero as well as setting the abort flag.   */
  139. /*                                                                          */
  140. /*    V3.08   Revised                   01-DEC-1990  Richard B. Johnson     */
  141. /*                                                                          */
  142. /*      (1)   Changed the code to compile without warning errors when       */
  143. /*            using Microsoft Version 6.0. They saw fit to change the       */
  144. /*            ANSI standards for declaring objects passed to functions.     */
  145. /*            The new "standards" were called to my attention by            */
  146. /*            Jeff Jevnisek who provided modified source.                   */
  147. /*                                                                          */
  148. /*      (2)   Changed the method of determining a memory allocation         */
  149. /*            failure. The code used to check for a NULL pointer returned   */
  150. /*            from _malloc() if memory was not available. Microsoft does    */
  151. /*            not allow NULL to be used for that anymore! Instead I have    */
  152. /*            to either use a cast or check for (!ptr). I chose the latter. */
  153. /*                                                                          */
  154. /*    V3.09   Revised                   27-JUN-1991  Richard B. Johnson     */
  155. /*                                                                          */
  156. /*      (1)   Changed a typo in the previous revision record that showed    */
  157. /*            the date to be 01-DEC-1991 when it should be 01-DEC-1990      */
  158. /*                                                                          */
  159. /*      (2)   Changed the method of checking the interrupt buffer pointer   */
  160. /*            in JMODEM_E.C so that only one compare and no arithmetic      */
  161. /*            has to be done. JMODEM now works at 38,400 baud with a        */
  162. /*            33 MHz '386 machine.                                          */
  163. /*                                                                          */
  164. /*      (3)   Added support for using any communications port address       */
  165. /*            and IRQ.                                                      */
  166. /*                                                                          */
  167. /*            JMODEM R(3F8:4) filename.typ                                  */
  168. /*            JMODEM R(2F8:3) filename.typ                                  */
  169. /*            JMODEM S(3F8:4) filename.typ                                  */
  170. /*            JMODEM S(2F8:3) filename.typ                                  */
  171. /*            JMODEM S(20E:7) filename.typ  ... etc.                        */
  172. /*                                                                          */
  173. /*    V3.10   Revised                   19-NOV-1991  Richard B. Johnson     */
  174. /*                                                                          */
  175. /*      (1)   Changed the memory allocation method. Used to allocate 4      */
  176. /*            buffers with 4 calls to _malloc(). Now I allocate one large   */
  177. /*            block and cut it up into 4 pieces. This is more efficient.    */
  178. /*                                                                          */
  179. /*      (2)   Called _malloc() directly without a separate allocate_mem()   */
  180. /*            routine because machine differences can be handled with       */
  181. /*            definitions for different compilers and platforms.            */
  182. /*                                                                          */
  183. /*      (3)   Moved the receive and timer interrupt service routines to     */
  184. /*            assembly-language modules in JMODEM_G.ASM                     */
  185. /*                                                                          */
  186. /*    V3.11   Revised                   25-JAN-1992  Richard B. Johnson     */
  187. /*                                                                          */
  188. /*      (1)   Added variable "tries" to force a timeout should the user     */
  189. /*            attempt to receive from a disconnected RS-232C line. This     */
  190. /*            will time-out in about a minute.                              */
  191. /*                                                                          */
  192. /*                                                                          */
  193. /****************************************************************************/
  194. #include <stdlib.h>                     /* Used for _free()                 */
  195. #include <stdio.h>                      /* Used for NULL value              */
  196. #include <string.h>                     /* Used for _memcpy()               */
  197. #include <time.h>                       /* Used for absolute time           */
  198. #include "jmodem.h"                     /* JMODEM primatives                */
  199. #if defined (TURBOC)
  200.     #include <alloc.h>
  201. #else
  202.     #include <malloc.h>                 /* Used for _malloc();              */
  203. #endif
  204.  
  205. /****************************************************************************/
  206. /*                   Global pointers and allocation                         */
  207. /****************************************************************************/
  208. word user_abort = 0;                    /* Global user abort flag           */
  209. byte *int_buffer;                       /* Pointer to interrupt buffer      */
  210. SYS syst;                               /* Structure for JMODEM status      */
  211. /****************************************************************************/
  212. /*                               C O D E                                    */
  213. /****************************************************************************/
  214. short main (short argc,  char *argv[])
  215. {
  216.     byte *in_buffer;                      /* Pointer to input buffer        */
  217.     byte *out_buffer;                     /* Pointer to output buffer       */
  218.     byte *comp_buffer;                    /* Pointer to compression buffer  */
  219.     register byte *io_ptr;                /* Select buffers to use for I/O  */
  220.     register JBUF *buff;                  /* A pointer for the JMODEM block */
  221.     byte *file_name;                      /* Filename                       */
  222.     byte function;                        /* Receive, Transmit              */
  223.     time_t start;                         /* Start time                     */
  224.     time_t finish;                        /* End time                       */
  225. #ifdef FTIME                              /* Floating point timer           */
  226.     double dat_tmp;                       /* Temporary variable for time    */
  227. #endif
  228.     word status=0;                        /* TX and RX status               */
  229.     word tries;                           /* Attempts to send a file        */
  230.     word cmp_size;                        /* Size after compression         */
  231.     word data_written;                    /* Data written to the file       */
  232.     word data_read;                       /* Data read from the file        */
  233.     short handle;                         /* For file I/O                   */
  234.  
  235.     if (!(file_name = get_inp (argc, argv))) /* Get file name               */
  236.     {
  237.         disp();                              /* Display usage message       */
  238.         return JM_FNF;
  239.     }
  240.     if (!(function = get_fun (argc, argv)))  /* Get function 'R' or 'S'     */
  241.     {
  242.         disp();                              /* Display usage message       */
  243.         return JM_CMD;
  244.     }
  245.     if (!(port = get_port (argc, argv)))     /* Get port '1 to 4 '          */
  246.     {
  247.         disp();                              /* Display usage message       */
  248.         return JM_CMD;
  249.     }
  250. /****************************************************************************/
  251. /*                          Allocate buffers                                */
  252. /*  Note: Here I allocate one large buffer that is 4 times the size of      */
  253. /*        DAT_LEN. Then I partition it into 4 sections for the 4 buffers.   */
  254. /*        This is more efficient that multiple calls to _malloc() and I     */
  255. /*        can free the entire buffer with one call to _free().              */
  256. /****************************************************************************/
  257.     in_buffer = (byte *) malloc(ALC_MEM);  /* Get some memory for input     */
  258.     if (!in_buffer)
  259.         return JM_MEM;                     /* No memory available           */
  260.     out_buffer = in_buffer   + DAT_LEN;    /* Get some memory for output    */
  261.     comp_buffer= out_buffer  + DAT_LEN;    /* Get memory for compression    */
  262.     int_buffer = comp_buffer + DAT_LEN;    /* Memory for interrupt buffer   */
  263. /****************************************************************************/
  264.     screen (SCR_SGN);                      /* Write signon screen           */
  265.     syst.s_len = BLK_SIZ;                  /* Set beginning block size      */
  266.     syst.s_byt = 0;                        /* Set bytes handled             */
  267.     syst.s_blk = 0;                        /* Starting block                */
  268.     syst.s_sta = okay;                     /* Starting status               */
  269.     switch(function)                       /* Functions are TX and RX       */
  270.     {
  271. /****************************************************************************/
  272. /*                          Receive JMODEM file                             */
  273. /****************************************************************************/
  274.     case 'R':
  275.         {
  276.             if (!file_io(CREATE, &handle, file_name) )
  277.             {
  278.                 buff = (JBUF *) in_buffer;           /* Assign type JBUF    */
  279.                 open_chan(port);                     /* Open com channel    */
  280.                 screen (SCR_STA);                    /* Write status block  */
  281.                 status = rx_sync();                  /* Synchronize         */
  282.                 if (!status)
  283.                     screen (SCR_SYR);
  284.                 data_written = 0xFFFF;
  285.                 tries = 10;                          /* Attempts to receive */
  286.                 while (    (data_written)            /* Write file okay     */
  287.                         && (!user_abort )            /* No break key        */
  288.                         && (!status     )            /* Recev block okay    */
  289.                         && (tries--)    )            /* 10 retries          */
  290.                 {
  291.                     time(&start);                    /* Get starting time   */
  292.                     screen (SCR_SYS,&syst);          /* Show status block   */
  293.                     status = recv_blk (              /* Receive data-block  */
  294.                              &syst.s_len,            /* Block length        */
  295.                              in_buffer);             /* Input buffer        */
  296.                     if (status)                      /* If bad              */
  297.                         break;                       /* Abort the WHILE     */
  298.                     if( (!(calc_crc( GET_CRC,        /* Calculate CRC       */
  299.                           syst.s_len,                /* Amount to check     */
  300.                           in_buffer) ))              /* Receiver buffer     */
  301.                       && ( buff->blk_num ==          /* Check block also    */
  302.                          (byte)
  303.                          (syst.s_blk +1)))           /* Block number        */
  304.                     {
  305.                         syst.s_sta = okay;           /* Text pointer        */
  306.                         tries=10;                    /* Reset count         */
  307.                         syst.s_len -= OVRHD;         /* Subtract overhead   */
  308.                         *out_buffer = ACK;           /* Good                */
  309.                         write_chan(1,out_buffer);    /* Send the ACK        */
  310.                         io_ptr = &buff->blk_dat;     /* Assume normal data  */
  311.  
  312.                         if (buff->blk_typ & COMP)
  313.                         {                            /* If data compressed  */
  314.                              syst.s_len = decode (   /* Decode the data     */
  315.                                       syst.s_len,    /* Data-block length   */
  316.                                      &buff->blk_dat, /* Where to start      */
  317.                                      comp_buffer);   /* Where to put data   */
  318.                              io_ptr = comp_buffer;   /* Point to data       */
  319.                         }
  320.                         data_written = file_io(WRITE, /* Write to file      */
  321.                                          &handle,     /* File handle        */
  322.                                          io_ptr ,     /* Where data is      */
  323.                                          syst.s_len); /* Amount to write    */
  324.                         syst.s_byt += data_written;   /* Total bytes        */
  325.                         syst.s_blk++;                 /* Block number       */
  326.                         time(&finish);                /* Get end time       */
  327.                         if (finish - start)           /* Check div/0        */
  328.                         {
  329. #ifdef FTIME
  330.                             dat_tmp = (double) data_written;
  331.                             syst.s_cps = (short) (dat_tmp /
  332.                                                difftime(finish,start));
  333. #else
  334.                             syst.s_cps = (short)      /* Calc Block CPS     */
  335.                             (data_written / (finish - start) );
  336. #endif
  337.                         }
  338.                                                        /* Check end-of-file */
  339.                         if (buff->blk_typ & EOF_)
  340.                         {
  341.                             file_io(CLOSE,&handle);   /* Close file         */
  342.                             close_chan(port);         /* Close the port     */
  343.                             status = JM_NRM;          /* Set status         */
  344.                             goto cleanup;             /* exit routine       */
  345.                         }
  346.                     }
  347.                     else
  348.                     {
  349.                         *out_buffer = NAK;            /* Bad block          */
  350.                         syst.s_sta = retry;           /* Char pointer       */
  351.                         write_chan(1,out_buffer);     /* Send the NAK       */
  352.                      }
  353.                 }
  354.                 close_chan(port);                     /* Aborted            */
  355.                 file_io( DELETE, &handle, file_name); /* Delete bad file    */
  356.                 status = JM_ABT;
  357.                 break;                                /* Exit if() {}       */
  358.             }
  359.             else                                      /* Can't create file  */
  360.             {
  361.                 status = JM_CRE;
  362.                 break;                                /* Exit while() {}    */
  363.             }
  364.         }
  365. /****************************************************************************/
  366. /*                          Send JMODEM file                                */
  367. /****************************************************************************/
  368.     case 'S':   /* Send JMODEM file */
  369.         {
  370.             if (!file_io(OPEN_READ, &handle, file_name) )
  371.             {
  372.                 buff = (JBUF *)out_buffer;            /* Assign type JBUF   */
  373.                 syst.s_byt = 0;                       /* Restore byte count */
  374.                 open_chan(port);                      /* Open COM port      */
  375.                 screen (SCR_STA);                     /* Write status block */
  376.                 status = tx_sync();                   /* Synchronize        */
  377.                 if (!status)
  378.                     screen (SCR_SYT);
  379.                 while  ( (!user_abort)                /* Ctrl - break       */
  380.                        && (!status) )                 /* sent okay          */
  381.                 {
  382.                     time(&start);                     /* Get starting time  */
  383.                     data_read = file_io( READ,        /* Read a record      */
  384.                                       &handle,        /* File pointer       */
  385.                                       &buff->blk_dat, /* Where to put data  */
  386.                                       syst.s_len );   /* Amount to read     */
  387.                     if (!data_read)                   /* Past end of file   */
  388.                         break;
  389.                     syst.s_byt += (long) data_read;   /* Running count      */
  390.                     screen (SCR_SYS,&syst);           /* Show status block  */
  391.                     buff->blk_num = (byte)
  392.                                      ++syst.s_blk;    /* Block number       */
  393.                     buff->blk_typ = NORM;             /* Assume Normal      */
  394.                     buff->len = (data_read+OVRHD);    /* Length of block    */
  395.                     if (data_read != syst.s_len)      /* Less than request  */
  396.                         buff->blk_typ |= EOF_;        /* Its end of file    */
  397.                     cmp_size = encode (data_read,     /* Encode size        */
  398.                                       &buff->blk_dat, /* Source             */
  399.                                       comp_buffer);   /* Destination        */
  400.                     if ( cmp_size  < data_read  )     /* If compressed      */
  401.                     {
  402.                         buff->len = (cmp_size+OVRHD); /* Length of block    */
  403.                         buff->blk_typ |= COMP;        /* Show compressed    */
  404.                         memcpy (&buff->blk_dat,       /* Start of data      */
  405.                                    comp_buffer,       /* Copy from here     */
  406.                                    cmp_size);         /* This much          */
  407.                     }
  408.                     calc_crc(SET_CRC,                 /* Calculate CRC      */
  409.                             buff->len ,               /* Length of block    */
  410.                             out_buffer);              /* Where data is      */
  411.                     status = send_blk(                /* Send the block     */
  412.                              buff->len,               /* Block length       */
  413.                              &syst,                   /* Read block ptr.    */
  414.                              out_buffer);             /* Buffer pointer     */
  415.                     time(&finish);                    /* Get end time       */
  416.                     if (finish - start)               /* Check div/0        */
  417.                     {
  418. #ifdef FTIME
  419.                         dat_tmp = (double) data_read;
  420.                         syst.s_cps = (short) (dat_tmp /
  421.                                      difftime(finish,start));
  422. #else
  423.                         syst.s_cps = (short)          /* Calc Block CPS     */
  424.                         (data_read / (finish - start) );
  425. #endif
  426.                     }
  427.                     if ( buff->blk_typ == EOF_)       /* Last record        */
  428.                         break;
  429.                 }
  430.                 syst.s_sta = done;                    /* Assume normal      */
  431.                 if (status)
  432.                 {
  433.                     cancel();                         /* Send ^Xes          */
  434.                     syst.s_sta = abrt;                /* Was aborted        */
  435.                 }
  436.                 close_chan(port);                     /* Close the port     */
  437.                 file_io(CLOSE, &handle);              /* Close the file     */
  438.                 screen (SCR_SYS,&syst);               /* Show status block  */
  439.             }
  440.             else                                      /* File not found     */
  441.             {
  442.                 status = JM_FNF;
  443.             }
  444.         break;                                        /*   End of CASE 'S'  */
  445.         }
  446.     }
  447.     cleanup:
  448.     free (in_buffer);                                 /* Free  buffers      */
  449.                               /* Two-second timer to display error messages */
  450.     if (status != JM_NRM)
  451.     {
  452.         time(&finish);                               /* Get system clock    */
  453.         finish += 2;                                 /* Add two seconds     */
  454.         start = 0;
  455.         while ( finish > start )                     /* Wait until the same */
  456.             time(&start);
  457.     }
  458.     screen (SCR_END);                                /* Clear the screen    */
  459.     return status;                                   /* Normal exit         */
  460. }
  461. /****************************************************************************/
  462. /*                          Send the JMODEM block                           */
  463. /****************************************************************************/
  464. word send_blk (word blk_len, register SYS *sys_ptr, register byte *buffer)
  465. {
  466.     byte ack_buf;                         /* Buffer for ACK/NAK             */
  467.     word tries = 10;                      /* Attempts to send the block     */
  468.     while ((tries--) && (!user_abort))
  469.     {
  470.         write_chan(blk_len,buffer);       /* Send the JMODEM block          */
  471.         flush();                          /* Clear back channel noise       */
  472.         do
  473.         {
  474.             ack_buf = (char) 0x00;        /* Clear the return buffer        */
  475.             read_chan(1,&ack_buf);        /* Receive a response             */
  476.         } while ( (ack_buf != ACK)        /* Stay in loop until we          */
  477.                && (ack_buf != CAN)        /*  ... get something useful      */
  478.                && (ack_buf != NAK)        /* This helps re-sync in noise    */
  479.                && (ack_buf == (char) 0x00)
  480.                && (!user_abort) );
  481.  
  482.         if ( (ack_buf == CAN)
  483.            || user_abort )                /* Check for an abort             */
  484.             break;                        /* User aborted                   */
  485.         if (ack_buf == ACK)               /* If good block                  */
  486.         {
  487.             if (tries == 9)               /* If no retries                  */
  488.             {
  489.                 sys_ptr->s_len += 512;    /* Increase block-size            */
  490.                 if (sys_ptr->s_len > DAT_MAX) /* If too large               */
  491.                     sys_ptr->s_len = DAT_MAX;
  492.             }
  493.             else
  494.             {
  495.                 tries = 9 - tries;        /* Use for divisor                */
  496.                 sys_ptr->s_len =          /* Update block length            */
  497.                 sys_ptr->s_len / tries;   /* Div block size                 */
  498.             if (sys_ptr->s_len < 0x40)    /* If less than minimum           */
  499.                 sys_ptr->s_len = 0x40;    /* Set to minimum                 */
  500.             }
  501.         sys_ptr->s_sta = okay;            /* Show status is okay            */
  502.         return JM_NRM;                    /* Show good                      */
  503.         }
  504.     sys_ptr->s_sta = retry;               /* Show a retry                   */
  505.     screen (SCR_SYS, sys_ptr);            /* Write to screen                */
  506.     }
  507.     cancel();                             /* Send cancel (^Xes)             */
  508.     return JM_ABT;                        /* Abort local program            */
  509. }
  510. /****************************************************************************/
  511. /*                        Receive the JMODEM block                          */
  512. /****************************************************************************/
  513. word recv_blk (word *blk_len, register byte *buffer)
  514. {
  515.     register JBUF *buff;                  /* Pointer type JBUF              */
  516.     byte nak_buf;                         /* Buffer for ACK/NAK             */
  517.     word tries = 10;                      /* Attempts to receive the block  */
  518.     word ret_val;                         /* Block length returned          */
  519.     buff = (JBUF * )buffer;               /* Assign pointer type JBUF       */
  520.  
  521.     while ((tries--) && (!user_abort))
  522.     {
  523.         ret_val = read_chan(2,buffer);    /* Receive the block size         */
  524.         if (ret_val == 2)                 /* If we received the length      */
  525.         {
  526.             *blk_len = buff->len;         /* So caller knows size           */
  527.             if (*blk_len > DAT_LEN)       /* If way out of line             */
  528.                 break;                    /* NAK it                         */
  529.             ret_val = read_chan(          /* Get more data                  */
  530.                       (*blk_len)-2 ,      /* Size to read                   */
  531.                       &buff->blk_typ);    /* Where to put it                */
  532.             if (ret_val == (*blk_len)-2)  /* If we got what we requested    */
  533.                 return JM_NRM;
  534.         }
  535.     if (buff->blk_typ == CAN)             /* If transmitter sent ^Xes       */
  536.         break;                            /* The other side has aborted     */
  537.     read_chan (DAT_LEN,buffer);           /* Make sure other end stops      */
  538.     nak_buf = NAK;                        /* Get a NAK                      */
  539.     write_chan(1,&nak_buf);               /* Send to remote                 */
  540.     flush();                              /* Flush the buffer               */
  541.     }
  542.     cancel();                             /* Send cancel (^Xes)             */
  543.     return JM_ABT;                        /* Abort local program            */
  544. }
  545. /****************************************************************************/
  546. /*                         Synchronize during receive                       */
  547. /****************************************************************************/
  548. word rx_sync()
  549. {
  550.     word tries;                           /* Attempts to synchronize        */
  551.     byte ack_nak;                         /* Single byte buffer for ACK/NAK */
  552.     flush();                              /* Clear the interrupt buffer     */
  553.     tries = TRIES;                        /* Attempts to synchronize        */
  554.     while ((!user_abort) && (tries--))
  555.     {
  556.         ack_nak = (char) 0x00;            /* Clear the buffer               */
  557.         read_chan(1,&ack_nak);            /* Receive ACK, NAK, or SYN       */
  558.         if (ack_nak == CAN)               /* If a ^X                        */
  559.             break;
  560.         if ( ack_nak == ACK )             /* If a good response             */
  561.             return JM_NRM;                /* Show handshake                 */
  562.         if ( ack_nak == NAK )             /* If a good response             */
  563.         {
  564.             ack_nak = ACK;
  565.             write_chan(1,&ack_nak);       /* Send a ACK response            */
  566.             return JM_NRM;
  567.          }
  568.          ack_nak = NAK;
  569.          write_chan(1,&ack_nak);          /* Keep sending NAKs              */
  570.     }
  571.     cancel();                             /* Send cancel (^Xes)             */
  572.     return JM_ABT;
  573. }
  574. /****************************************************************************/
  575. /*                           Send ^Xes to cancel                            */
  576. /****************************************************************************/
  577. void cancel()
  578. {
  579.     byte buffer = CAN;
  580.     short xes = 6;
  581.     user_abort=0;                         /* Reset flag so write_chan works */
  582.     while(xes--)
  583.         write_chan(1,&buffer);
  584. }
  585. /****************************************************************************/
  586. /*                         Synchronize during transmit                      */
  587. /****************************************************************************/
  588. word tx_sync()
  589. {
  590.     word ret_val;
  591.     ret_val = rx_sync();                /* Call same routine for receive    */
  592.     if (!ret_val)                       /* If success                       */
  593.     {
  594.         flush();                        /* Flush the input buffer           */
  595.         timer = 5;                      /* 5 timer-ticks to wait            */
  596.         while (timer);                  /* Wait for timer                   */
  597.     }
  598.     return ret_val;                     /* Return status                    */
  599. }
  600. /****************************************************************************/
  601. /*     Dummy _setenvp procedure to replace the large library module         */
  602. /****************************************************************************/
  603. #ifdef NOENV                            /* If a compiler command            */
  604. void _setenvp(void);                    /* Dummy routine prototype          */
  605. void _setenvp()                         /* Dummy routine                    */
  606. {}
  607. #endif
  608. /****************************************************************************/
  609. /************************ E N D  O F   M O D U L E **************************/
  610.