home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1996 October / PCO_10.ISO / filesbbs / bsrc_260.arj / SRC.ZIP / xmsend.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-20  |  18.8 KB  |  860 lines

  1. /*--------------------------------------------------------------------------*/
  2. /*                                                                          */
  3. /*                                                                          */
  4. /*      ------------         Bit-Bucket Software, Co.                       */
  5. /*      \ 10001101 /         Writers and Distributors of                    */
  6. /*       \ 011110 /          Freely Available<tm> Software.                 */
  7. /*        \ 1011 /                                                          */
  8. /*         ------                                                           */
  9. /*                                                                          */
  10. /*              (C) Copyright 1987-96, Bit Bucket Software Co.              */
  11. /*                                                                          */
  12. /*                  This module was written by Bob Hartman                  */
  13. /*                                                                          */
  14. /*                 BinkleyTerm Xmodem Sender State Machine                  */
  15. /*                                                                          */
  16. /*                                                                          */
  17. /*    For complete  details  of the licensing restrictions, please refer    */
  18. /*    to the License  agreement,  which  is published in its entirety in    */
  19. /*    the MAKEFILE and BT.C, and also contained in the file LICENSE.260.    */
  20. /*                                                                          */
  21. /*    USE  OF THIS FILE IS SUBJECT TO THE  RESTRICTIONS CONTAINED IN THE    */
  22. /*    BINKLEYTERM  LICENSING  AGREEMENT.  IF YOU DO NOT FIND THE TEXT OF    */
  23. /*    THIS  AGREEMENT IN ANY OF THE  AFOREMENTIONED FILES,  OR IF YOU DO    */
  24. /*    NOT HAVE THESE FILES,  YOU  SHOULD  IMMEDIATELY CONTACT BIT BUCKET    */
  25. /*    SOFTWARE CO.  AT ONE OF THE  ADDRESSES  LISTED BELOW.  IN NO EVENT    */
  26. /*    SHOULD YOU  PROCEED TO USE THIS FILE  WITHOUT HAVING  ACCEPTED THE    */
  27. /*    TERMS  OF  THE  BINKLEYTERM  LICENSING  AGREEMENT,  OR  SUCH OTHER    */
  28. /*    AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO.      */
  29. /*                                                                          */
  30. /*                                                                          */
  31. /* You can contact Bit Bucket Software Co. at any one of the following      */
  32. /* addresses:                                                               */
  33. /*                                                                          */
  34. /* Bit Bucket Software Co.        FidoNet  1:104/501, 1:343/491             */
  35. /* P.O. Box 460398                AlterNet 7:42/1491                        */
  36. /* Aurora, CO 80046               BBS-Net  86:2030/1                        */
  37. /*                                Internet f491.n343.z1.fidonet.org         */
  38. /*                                                                          */
  39. /* Please feel free to contact us at any time to share your comments about  */
  40. /* our software and/or licensing policies.                                  */
  41. /*                                                                          */
  42. /*--------------------------------------------------------------------------*/
  43.  
  44. /* Include this file before any other includes or defines! */
  45.  
  46. #include "includes.h"
  47.  
  48. void 
  49. Build_Header_Block (XMARGSP args, char type)
  50. {
  51.     struct FILEINFO dta = {0};
  52.     SEADATAP ttmp;
  53.  
  54.     (void) dfind (&dta, args->filename, 0);
  55.     args->save_header = type;
  56.     ttmp = (SEADATAP) & (args->header);
  57.  
  58.     (void) memset (ttmp, 0, sizeof (XMDATA));
  59.     ttmp->header = type;
  60.     ttmp->block_num = 0;
  61.     ttmp->block_num_comp = 0xff;
  62.     ttmp->filelength = args->filelen;
  63.     (void) strncpy (ttmp->sendingprog, xfer_id, 14);
  64.     if (type == SYN)
  65.     {
  66.         (void) memset (ttmp->filename, ' ', 16);
  67.         ttmp->timedate = dta.time;
  68.         /* This is the CRC bit in the TeLink header */
  69.         ttmp->Resync = 1;
  70.     }
  71.     else
  72.     {
  73. #ifdef ANSI_TIME_T
  74.         ttmp->timedate = args->save_filetime.oneword.timedate - ANSI_TIME_T_DELTA;
  75. #else
  76.         ttmp->timedate = args->save_filetime.oneword.timedate;
  77. #endif
  78.         ttmp->SLO = (unsigned char) (((cur_baud.rate_value >= 9600L) && !no_overdrive) ? 1 : 0);
  79.         ttmp->Resync = (unsigned char) (no_resync ? 0 : 1);
  80.         ttmp->MACFLOW = 1;
  81.     }
  82.     if (args->temp_name != NULL)
  83.         (void) strncpy (ttmp->filename, args->temp_name, strlen (args->temp_name));
  84.     else
  85.         (void) strncpy (ttmp->filename, (char *) (dta.name), strlen (dta.name));
  86.  
  87.     (void) dfind (&dta, NULL, 2);
  88. }
  89.  
  90. void XSSetVars (XMARGSP);
  91. int XSInit (XMARGSP);
  92. int XSEnd (XMARGSP);
  93. int XSXmtStart (XMARGSP);
  94. int XSXmTeStrt (XMARGSP);
  95. int XSCheckACK (XMARGSP);
  96. int XSSendBlk (XMARGSP);
  97. int XSWaitEnd (XMARGSP);
  98.  
  99. typedef struct
  100. {
  101.     char *state_name;
  102.     int (*state_func) (XMARGSP);
  103. } XSTATES, *XSTATEP;
  104.  
  105. XSTATES Xmodem_Sender[] =
  106. {
  107.     {"XSInit", XSInit},
  108.     {"XSEnd", XSEnd},
  109.     {"XS0", XSXmtStart},
  110.     {"XS0T", XSXmTeStrt},
  111.     {"XS1", XSCheckACK},
  112.     {"XS2", XSSendBlk},
  113.     {"XS3", XSWaitEnd}
  114. };
  115.  
  116. int 
  117. XSInit (XMARGSP args)
  118. {
  119.     struct stat st;
  120.     char junkbuff[100];
  121.  
  122.     /* Get the file information */
  123.     if (stat (args->filename, &st))
  124.     {
  125.         /* Print error message */
  126.         return (OPEN_ERR);
  127.     }
  128.  
  129.     if ((args->file_pointer = share_fopen (args->filename, read_binary, DENY_WRITE)) == NULL)
  130.     {
  131.         /* Print error message */
  132.         return (OPEN_ERR);
  133.     }
  134.  
  135.     /* Get important information out of it */
  136.     args->filelen = st.st_size;
  137.     args->LastBlk = (st.st_size + 127) / 128;
  138.     args->save_filetime.oneword.timedate = st.st_atime;
  139.     args->prev_bytes = 0L;
  140.     args->tot_errs = 0;
  141.  
  142.     (void) sprintf (junkbuff, MSG_TXT (M_SEND_MSG), args->LastBlk, args->filename, st.st_size);
  143.     if (un_attended && fullscreen)
  144.     {
  145.         clear_filetransfer ();
  146.         sb_move (filewin, 1, 2);
  147.         sb_puts (filewin, junkbuff);
  148.         elapse_time ();
  149.         sb_show ();
  150.     }
  151.     else
  152.     {
  153.         status_line ("+%s", junkbuff);
  154.         (void) printf ("\n");
  155.     }
  156.  
  157.     locate_y = wherey ();
  158.     locate_x = wherex ();
  159.  
  160.     /* Start the throughput calculations */
  161.     throughput (0, 0L);
  162.     return ((int) args->control);
  163. }
  164.  
  165. int 
  166. XSEnd (XMARGSP args)
  167. {
  168.     args->result = (int) args->control;
  169.  
  170.     /* Close file */
  171.     (void) fclose (args->file_pointer);
  172.  
  173.     if (args->tot_errs > 3)
  174.         status_line (MSG_TXT (M_CORRECTED_ERRORS), args->tot_errs, args->LastBlk);
  175.  
  176.     /* Log that we sent it */
  177.     if (args->result == SUCCESS)
  178.     {
  179.         long lTime, lSize;
  180.  
  181.         lSize = args->filelen - args->prev_bytes;
  182.         lTime = throughput (1, (unsigned long) lSize);
  183.         status_line ("%s: %s", MSG_TXT (M_FILE_SENT), args->filename);
  184.         update_files (1, args->filename, lSize, lTime, 0);
  185.     }
  186.  
  187.     return (args->result);
  188. }
  189.  
  190. void 
  191. XSSetVars (XMARGSP args)
  192. {
  193.     if (no_sealink)
  194.     {
  195.         args->options.SLO = 0;
  196.         args->options.Resync = 0;
  197.     }
  198.     else
  199.     {
  200.         args->options.SLO = ((cur_baud.rate_value >= 9600L) && !no_overdrive) ? 1 : 0;
  201.         args->options.Resync = (~no_resync) & 1;
  202.     }
  203.  
  204.     args->options.SEAlink = 0;
  205.     args->SendBLK = 1;
  206.     args->curr_byte = 0L;
  207.     args->NextBLK = 1;
  208.     args->ACKST = 0;
  209.     args->ACKBLK = -1L;
  210.     args->Window = 1;
  211.     args->ACKsRcvd = 0;
  212.     args->NumNAK = 0;
  213.     args->T1 = timerset (3000);
  214. }
  215.  
  216. int 
  217. XSXmtStart (XMARGSP args)
  218. {
  219.     XSSetVars (args);
  220.     Build_Header_Block (args, SOH);
  221.     return (XS1);
  222. }
  223.  
  224. int 
  225. XSXmTeStrt (XMARGSP args)
  226. {
  227.     XSSetVars (args);
  228.     Build_Header_Block (args, SYN);
  229.     return (XS1);
  230. }
  231.  
  232. int 
  233. XSCheckACK (XMARGSP args)
  234. {
  235.     Check_ACKNAK (args);
  236.     return (XS2);
  237. }
  238.  
  239. int 
  240. XSSendBlk (XMARGSP args)
  241. {
  242.     if (!CARRIER)
  243.         return (CARRIER_ERR);
  244.  
  245.     if (got_ESC ())
  246.     {
  247.         status_line (MSG_TXT (M_KBD_MSG));
  248.         return (KBD_ERR);
  249.     }
  250.  
  251.     if ((args->NumNAK > 4) && (args->SendBLK == 0))
  252.     {
  253.         if (args->save_header == SOH)
  254.             return (XS0T);
  255.         else
  256.         {
  257.             args->NumNAK = 0;
  258.             ++(args->ACKBLK);
  259.             ++(args->SendBLK);
  260.             return (XS2);
  261.         }
  262.     }
  263.  
  264.     if (args->NumNAK > 10)
  265.     {
  266.         /* Too Many Errors */
  267.         return (SEND_RETRY_ERR);
  268.     }
  269.  
  270.     if (timeup (args->T1))
  271.     {
  272.         /* Fatal Timeout */
  273.         return (SEND_TIMEOUT);
  274.     }
  275.  
  276.     if (args->SendBLK > (args->LastBlk + 1))
  277.         return (XS3);
  278.  
  279.     if (args->SendBLK > (args->ACKBLK + args->Window))
  280.     {
  281.         time_release ();
  282.         return (XS1);
  283.     }
  284.  
  285.     if (args->SendBLK == (args->LastBlk + 1))
  286.     {
  287.         SENDBYTE (EOT);
  288.         ++(args->SendBLK);
  289.         args->T1 = timerset (3000);
  290.         show_sending_blocks (args);
  291.         time_release ();
  292.         return (XS1);
  293.     }
  294.  
  295.     /*
  296.         Increment the block count before sending because we read the next
  297.         block immediately after sending this block.  On error free connects
  298.         we have a big net win because we never do a seek, and while we are
  299.         sending one block, we read the next.  If we do get errors, then we
  300.         have to seek back to the previous block, and that will be a bother.
  301.         With today's phone lines and modems, we'll assume error free is more
  302.         often than not, and take our chances.
  303.     */
  304.     if (args->options.SLO && args->options.SEAlink)
  305.     {
  306.         args->ACKBLK = args->SendBLK;
  307.     }
  308.  
  309.     ++(args->SendBLK);
  310.     args->curr_byte += 128L;
  311.     Send_Block (args);
  312.     args->T1 = timerset (6000);
  313.     return (XS1);
  314. }
  315.  
  316. int 
  317. XSWaitEnd (XMARGSP args)
  318. {
  319.     show_sending_blocks (args);
  320.  
  321.     if (args->ACKBLK < (args->LastBlk + 1))
  322.     {
  323.         time_release ();
  324.         return (XS1);
  325.     }
  326.  
  327.     if (!CARRIER)
  328.         return (CARRIER_ERR);
  329.  
  330.     return (SUCCESS);
  331. }
  332.  
  333. int 
  334. SEAlink_Send_File (char *filename, char *sendname)
  335. {
  336.     XMARGS xm;
  337.  
  338.     xm.filename = filename;
  339.     xm.temp_name = sendname;
  340.     return (state_machine ((STATEP) Xmodem_Sender, &xm, XS0));
  341. }
  342.  
  343. int 
  344. Xmodem_Send_File (char *filename, char *sendname)
  345. {
  346.     return (SEAlink_Send_File (filename, sendname));
  347. }
  348.  
  349. int 
  350. Telink_Send_File (char *filename, char *sendname)
  351. {
  352.     XMARGS xm;
  353.  
  354.     xm.filename = filename;
  355.     xm.temp_name = sendname;
  356.     return (state_machine ((STATEP) Xmodem_Sender, &xm, XS0T));
  357. }
  358.  
  359. void 
  360. Get_Block (XMARGSP args)
  361. {
  362.     XMDATAP xtmp;
  363.  
  364.     if (args->SendBLK == 0)
  365.     {
  366.         Build_Header_Block (args, args->save_header);
  367.         args->NextBLK = -1L;
  368.         return;
  369.     }
  370.  
  371.     xtmp = (XMDATAP) & (args->header);
  372.  
  373.     /* Set up buffer as all ^Zs for EOF */
  374.     (void) memset (xtmp, SUB, sizeof (XMDATA));
  375.  
  376.     /* Now set up the header stuff */
  377.     xtmp->header = SOH;
  378.     xtmp->block_num = (unsigned char) (args->SendBLK & 0xff);
  379.     xtmp->block_num_comp = (unsigned char) ~xtmp->block_num;
  380.  
  381.     if (args->NextBLK != args->SendBLK)
  382.     {
  383.         (void) fseek (args->file_pointer, (args->SendBLK - 1) * 128, SEEK_SET);
  384.     }
  385.  
  386.     args->NextBLK = args->SendBLK + 1;
  387.  
  388.     /* Can we read any data? */
  389.     if (fread ((char *) xtmp->data_bytes, 1, 128, args->file_pointer) <= 0)
  390.         return;
  391.  
  392.     /* Looks good */
  393.     return;
  394. }
  395.  
  396. void 
  397. Send_Block (XMARGSP args)
  398. {
  399.     if (args->header == SYN)
  400.     {
  401.         Data_Check ((XMDATAP) & (args->header), CHECKSUM);
  402.     }
  403.     else
  404.     {
  405.         Data_Check ((XMDATAP) & (args->header), args->options.do_CRC ? CRC : CHECKSUM);
  406.     }
  407.  
  408.     if ((!(args->options.do_CRC)) || (args->header == SYN))
  409.     {
  410.         SENDCHARS ((char *) &(args->header), sizeof (XMDATA) - 1, 1);
  411.     }
  412.     else
  413.     {
  414.         SENDCHARS ((char *) &(args->header), sizeof (XMDATA), 1);
  415.     }
  416.  
  417.     UNBUFFER_BYTES ();
  418.  
  419.     show_sending_blocks (args);
  420.  
  421.     Get_Block (args);
  422. }
  423.  
  424. char *
  425. show_num (XMARGSP args, long b)
  426. {
  427.     char *Rtn;
  428.  
  429.     Rtn = "EOT";
  430.     if (b > args->LastBlk)
  431.     {
  432.         if (!(fullscreen && un_attended))
  433.             (void) cputs (Rtn);
  434.     }
  435.     else if (b >= 0L)
  436.     {
  437.         Rtn = ultoa (((unsigned long) b), e_input, 10);
  438.         if (!(fullscreen && un_attended))
  439.             (void) cputs (Rtn);
  440.     }
  441.     return Rtn;
  442. }
  443.  
  444. void 
  445. show_sending_blocks (XMARGSP args)
  446. {
  447.     char *TmpPtr = (char *) &happy_compiler;
  448.     char j[100];
  449.     long k;
  450.  
  451.     k = args->filelen - args->curr_byte;
  452.     if (k < 0L)
  453.         k = 0L;
  454.  
  455.     (void) sprintf (j, "%3d min",
  456.         ((k * 10L / cur_baud.rate_value * 100L /
  457.         ((args->save_header == SOH) ? 94L : 70L) + 59L) / 60L));
  458.  
  459.     if (args->options.SLO)
  460.     {
  461.         if ((!((args->SendBLK - 1) & 0x1f)) || ((args->SendBLK - 1) > args->LastBlk))
  462.         {
  463.             if (fullscreen && un_attended)
  464.             {
  465.                 elapse_time ();
  466.                 sb_move (filewin, 2, 2);
  467.                 TmpPtr = show_num (args, args->SendBLK - 1);
  468.                 sb_puts (filewin, TmpPtr);
  469.                 (void) sb_putc (filewin, ':');
  470.                 TmpPtr = show_num (args, args->ACKBLK);
  471.                 sb_puts (filewin, TmpPtr);
  472.                 sb_puts (filewin, " *Overdrive*  ");
  473.                 sb_move (filewin, 2, 69);
  474.                 sb_puts (filewin, j);
  475.                 sb_show ();
  476.             }
  477.             else
  478.             {
  479.                 gotoxy (locate_x, locate_y);
  480.                 (void) show_num (args, args->SendBLK - 1);
  481.                 (void) cputs (":");
  482.                 (void) show_num (args, args->ACKBLK);
  483.                 (void) cputs (" *Overdrive*  ");
  484.             }
  485.         }
  486.     }
  487.     else
  488.     {
  489.         if (fullscreen && un_attended)
  490.         {
  491.             elapse_time ();
  492.  
  493.             sb_move (filewin, 2, 2);
  494.             TmpPtr = show_num (args, args->SendBLK - 1);
  495.             sb_puts (filewin, TmpPtr);
  496.             (void) sb_putc (filewin, ':');
  497.             TmpPtr = show_num (args, args->ACKBLK);
  498.             sb_puts (filewin, TmpPtr);
  499.  
  500.             sb_puts (filewin, "              ");
  501.             sb_move (filewin, 2, 69);
  502.             sb_puts (filewin, j);
  503.             sb_show ();
  504.         }
  505.         else
  506.         {
  507.             gotoxy (locate_x, locate_y);
  508.             (void) show_num (args, args->SendBLK - 1);
  509.             (void) cputs (":");
  510.             (void) show_num (args, args->ACKBLK);
  511.             (void) cputs ("              ");
  512.         }
  513.     }
  514.     happy_compiler = *(int *) TmpPtr;    /* Makes the compiler happy! */
  515. }
  516.  
  517. int ACInit (XMARGSP);
  518. int ACEnd (XMARGSP);
  519. int ACChkRcvd (XMARGSP);
  520. int ACSLCheck (XMARGSP);
  521. int ACSLVerify (XMARGSP);
  522. int ACSLACKNAK (XMARGSP);
  523. int ACXMCheck (XMARGSP);
  524. int ACSLOCheck (XMARGSP);
  525. int ACSL1Check (XMARGSP);
  526. int ACACKNAK (XMARGSP);
  527. int ACXMACK (XMARGSP);
  528. int ACXMNAK (XMARGSP);
  529. int ACRESYNC (XMARGSP);
  530.  
  531. typedef struct
  532. {
  533.     char *state_name;
  534.     int (*state_func) (XMARGSP);
  535. } ASTATES, *ASTATEP;
  536.  
  537. ASTATES ACKNAK_Check[] =
  538. {
  539.     {"ACInit", ACInit},
  540.     {"ACEnd", ACEnd},
  541.     {"AC0", ACChkRcvd},
  542.     {"AC1", ACSLCheck},
  543.     {"AC2", ACSLVerify},
  544.     {"AC3", ACSLACKNAK},
  545.     {"AC4", ACXMCheck},
  546.     {"AC5", ACSLOCheck},
  547.     {"AC6", ACSL1Check},
  548.     {"AC7", ACACKNAK},
  549.     {"AC8", ACXMACK},
  550.     {"AC9", ACXMNAK},
  551.     {"AC10", ACRESYNC}
  552. };
  553.  
  554. int 
  555. ACInit (XMARGSP args)
  556. {
  557.     args->result = 0;
  558.     return ((int) args->control);
  559. }
  560.  
  561. int 
  562. ACEnd (XMARGSP args)
  563. {
  564.     args->result = (int) args->control;
  565.     return (args->result);
  566. }
  567.  
  568. int 
  569. ACChkRcvd (XMARGSP args)
  570. {
  571.     if (PEEKBYTE () >= 0)
  572.     {
  573.         args->CHR = TIMED_READ (0);
  574.         return (AC1);
  575.     }
  576.  
  577.     return (SUCCESS);
  578. }
  579.  
  580. int 
  581. ACSLCheck (XMARGSP args)
  582. {
  583.     if (args->ACKST > 2)
  584.         return (AC2);
  585.  
  586.     return (AC6);
  587. }
  588.  
  589. int 
  590. ACSLVerify (XMARGSP args)
  591. {
  592.     if (args->ARBLK8 == (unsigned char) ((~args->CHR) & 0xff))
  593.     {
  594.         args->ARBLK = args->SendBLK - ((args->SendBLK - args->ARBLK8) & 0xff);
  595.         return (AC3);
  596.     }
  597.  
  598.     args->options.SEAlink = 0;
  599.     args->Window = 1;
  600.     args->ACKST = 0;
  601.     return (AC6);
  602. }
  603.  
  604. int 
  605. ACSLACKNAK (XMARGSP args)
  606. {
  607.     if ((args->ARBLK < 0)
  608.         || (args->ARBLK > args->SendBLK)
  609.         || (args->ARBLK <= (args->SendBLK - 128)))
  610.     {
  611.         return (AC0);
  612.     }
  613.  
  614.     if (args->ACKST == 3)
  615.     {
  616.         args->options.SEAlink = (~no_sealink) & 1;
  617.         args->Window = calc_window ();
  618.         args->ACKBLK = args->ARBLK;
  619.         ++(args->ACKsRcvd);
  620.         args->ACKST = 0;
  621.         return (AC5);
  622.     }
  623.  
  624.     args->SendBLK = args->ARBLK;
  625.     args->curr_byte = (args->SendBLK - 1) * 128L;
  626.     if (args->curr_byte < 0L)
  627.         args->curr_byte = 0L;
  628.  
  629.     if (args->SendBLK > 0)
  630.         ++(args->tot_errs);
  631.  
  632.     Get_Block (args);
  633.     args->ACKST = 0;
  634.  
  635.     return (AC4);
  636. }
  637.  
  638. int 
  639. ACXMCheck (XMARGSP args)
  640. {
  641.     if (args->NumNAK < 4)
  642.     {
  643.         args->options.SEAlink = (~no_sealink) & 1;
  644.         args->Window = calc_window ();
  645.     }
  646.     else
  647.     {
  648.         args->options.SEAlink = 0;
  649.         args->Window = 1;
  650.     }
  651.     return (SUCCESS);
  652. }
  653.  
  654. int 
  655. ACSLOCheck (XMARGSP args)
  656. {
  657.     if ((args->options.SLO == 0) || (args->ACKsRcvd < 10))
  658.         return (SUCCESS);
  659.  
  660.     args->options.SLO = 0;
  661.     return (SUCCESS);
  662. }
  663.  
  664. int 
  665. ACSL1Check (XMARGSP args)
  666. {
  667.     if ((args->ACKST == 1) || (args->ACKST == 2))
  668.     {
  669.         args->ARBLK8 = (unsigned char) args->CHR;
  670.         args->ACKST += 2;
  671.         return (AC6);
  672.     }
  673.  
  674.     if ((args->options.SEAlink == 0) || (args->ACKST == 0))
  675.         return (AC7);
  676.  
  677.     return (AC0);
  678. }
  679.  
  680. int 
  681. ACACKNAK (XMARGSP args)
  682. {
  683.     long mac_timer;
  684.  
  685.     switch (args->CHR)
  686.     {
  687.     case ACK:
  688.         args->ACKST = 1;
  689.         args->NumNAK = 0;
  690.         return (AC8);
  691.  
  692.     case WANTCRC:
  693.         args->options.do_CRC = 1;
  694.  
  695.         /* Fallthrough */
  696.  
  697.     case NAK:
  698.         args->ACKST = 2;
  699.         ++(args->NumNAK);
  700.         CLEAR_OUTBOUND ();
  701.         timer (6);
  702.         return (AC9);
  703.  
  704.     case SYN:
  705.         CLEAR_OUTBOUND ();
  706.         if (!no_resync)
  707.         {
  708.             args->result = Receive_Resync (&(args->resync_block));
  709.             args->ACKST = 0;
  710.             return (AC10);
  711.         }
  712.         else
  713.         {
  714.             return (AC0);
  715.         }
  716.  
  717.     case DC3:                    /* ^S */
  718.         if (args->options.SEAlink && (args->ACKST == 0))
  719.         {
  720.             mac_timer = timerset (1000);
  721.             while (CARRIER && !timeup (mac_timer))
  722.             {
  723.                 if (TIMED_READ (0) == DC1)
  724.                     break;
  725.  
  726.                 time_release ();
  727.             }
  728.             return (AC0);
  729.         }
  730.  
  731.         /* Otherwise, fallthrough */
  732.  
  733.     default:
  734.         break;
  735.     }
  736.     return (AC0);
  737. }
  738.  
  739. int 
  740. ACXMACK (XMARGSP args)
  741. {
  742.     if (!args->options.SEAlink)
  743.         ++(args->ACKBLK);
  744.  
  745.     return (AC0);
  746. }
  747.  
  748. int 
  749. ACXMNAK (XMARGSP args)
  750. {
  751.     if (!args->options.SEAlink)
  752.     {
  753.         args->SendBLK = args->ACKBLK + 1;
  754.         args->curr_byte = (args->SendBLK - 1) * 128L;
  755.         if (args->curr_byte < 0L)
  756.             args->curr_byte = 0L;
  757.  
  758.         if (args->SendBLK > 0)
  759.             ++(args->tot_errs);
  760.  
  761.         Get_Block (args);
  762.     }
  763.  
  764.     return (AC0);
  765. }
  766.  
  767. int 
  768. ACRESYNC (XMARGSP args)
  769. {
  770.     CLEAR_OUTBOUND ();
  771.     if (args->result != SUCCESS)
  772.     {
  773.         SENDBYTE (NAK);
  774.         return (SUCCESS);
  775.     }
  776.  
  777.     if (args->SendBLK == 1)
  778.     {
  779.         args->prev_bytes = (args->resync_block - 1) * 128;
  780.         if (args->prev_bytes > args->filelen)
  781.             args->prev_bytes = args->filelen;
  782.         status_line (MSG_TXT (M_SYNCHRONIZING), args->prev_bytes);
  783.     }
  784.     else
  785.     {
  786.         ++(args->tot_errs);
  787.     }
  788.  
  789.     args->options.SEAlink = 1;
  790.     args->Window = calc_window ();
  791.     args->SendBLK = args->resync_block;
  792.     args->curr_byte = (args->SendBLK - 1) * 128L;
  793.     if (args->curr_byte < 0L)
  794.         args->curr_byte = 0L;
  795.  
  796.     Get_Block (args);
  797.     args->ACKBLK = args->SendBLK - 1;
  798.     SENDBYTE (ACK);
  799.     return (SUCCESS);
  800. }
  801.  
  802. void 
  803. Check_ACKNAK (XMARGSP args)
  804. {
  805.     (void) state_machine ((STATEP) ACKNAK_Check, args, AC0);
  806. }
  807.  
  808. int 
  809. Receive_Resync (long *resync_block)
  810. {
  811.     unsigned char resyncit[30];
  812.     unsigned char *p;
  813.     unsigned char a, b;
  814.     unsigned short nak_crc, his_crc;
  815.  
  816.     p = resyncit;
  817.  
  818.     while ((*p = (unsigned char) TIMED_READ (1)) != ETX)
  819.     {
  820.         if ((*p < '0') || (*p > '9'))
  821.         {
  822.             status_line (">SEAlink Send: Resync bad byte '%02x'", *p);
  823.             return (RESYNC_ERR);
  824.         }
  825.         ++p;
  826.     }
  827.     *p = '\0';
  828.     nak_crc = crc_block ((unsigned char *) resyncit, (int) strlen ((char *) resyncit));
  829.     a = (unsigned char) TIMED_READ (1);
  830.     b = (unsigned char) TIMED_READ (1);
  831.     his_crc = (b << 8) | a;
  832.  
  833.     if (nak_crc != his_crc)
  834.     {
  835.         status_line (">SEAlink Send: Resync bad crc %04hx/%04hx", nak_crc, his_crc);
  836.         return (CRC_ERR);
  837.     }
  838.  
  839.     *resync_block = atol ((char *) resyncit);
  840.  
  841.     status_line (">SEAlink Send: Resync to %ld", *resync_block);
  842.     return (SUCCESS);
  843. }
  844.  
  845. int 
  846. calc_window ()
  847. {
  848.     long window;
  849.  
  850.     window = cur_baud.rate_value / 400L;
  851.     if (window <= 0L)
  852.         window = 2L;
  853.     if (small_window)
  854.         window = (window > 6L) ? 6L : window;
  855.     else
  856.         window = (window > 2000L) ? 2000L : window;
  857.  
  858.     return (int) window;
  859. }
  860.