home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / BTMTSRC3.ZIP / XMREC.C < prev    next >
Text File  |  1991-10-17  |  36KB  |  1,290 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-90, Bit Bucket Software Co., a Delaware Corporation. */
  11. /*                                                                          */
  12. /*                                                                          */
  13. /*                  This module was written by Bob Hartman                  */
  14. /*                                                                          */
  15. /*                                                                          */
  16. /*                BinkleyTerm Xmodem Receiver State Machine                 */
  17. /*                                                                          */
  18. /*                                                                          */
  19. /*    For complete  details  of the licensing restrictions, please refer    */
  20. /*    to the License  agreement,  which  is published in its entirety in    */
  21. /*    the MAKEFILE and BT.C, and also contained in the file LICENSE.240.    */
  22. /*                                                                          */
  23. /*    USE  OF THIS FILE IS SUBJECT TO THE  RESTRICTIONS CONTAINED IN THE    */
  24. /*    BINKLEYTERM  LICENSING  AGREEMENT.  IF YOU DO NOT FIND THE TEXT OF    */
  25. /*    THIS  AGREEMENT IN ANY OF THE  AFOREMENTIONED FILES,  OR IF YOU DO    */
  26. /*    NOT HAVE THESE FILES,  YOU  SHOULD  IMMEDIATELY CONTACT BIT BUCKET    */
  27. /*    SOFTWARE CO.  AT ONE OF THE  ADDRESSES  LISTED BELOW.  IN NO EVENT    */
  28. /*    SHOULD YOU  PROCEED TO USE THIS FILE  WITHOUT HAVING  ACCEPTED THE    */
  29. /*    TERMS  OF  THE  BINKLEYTERM  LICENSING  AGREEMENT,  OR  SUCH OTHER    */
  30. /*    AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO.      */
  31. /*                                                                          */
  32. /*                                                                          */
  33. /* You can contact Bit Bucket Software Co. at any one of the following      */
  34. /* addresses:                                                               */
  35. /*                                                                          */
  36. /* Bit Bucket Software Co.        FidoNet  1:104/501, 1:132/491, 1:141/491  */
  37. /* P.O. Box 460398                AlterNet 7:491/0                          */
  38. /* Aurora, CO 80046               BBS-Net  86:2030/1                        */
  39. /*                                Internet f491.n132.z1.fidonet.org         */
  40. /*                                                                          */
  41. /* Please feel free to contact us at any time to share your comments about  */
  42. /* our software and/or licensing policies.                                  */
  43. /*                                                                          */
  44. /*--------------------------------------------------------------------------*/
  45.  
  46.  
  47. /* System include files */
  48. #include <fcntl.h>
  49. #include <stdio.h>
  50. #include <string.h>
  51. #include <stdlib.h>
  52. #include <sys/types.h>
  53. #include <sys/stat.h>
  54. #include <dos.h>
  55. #include <time.h>
  56. #include <io.h>
  57. #include <ctype.h>
  58. #include <conio.h>
  59.  
  60. #ifdef __TURBOC__
  61. #include "tc_utime.h"
  62. #include <mem.h>
  63. #include <alloc.h>
  64. #else
  65. #include <sys/utime.h>
  66. #include <memory.h>
  67. #include <malloc.h>
  68. #endif
  69.  
  70. /* Local include files */
  71. #include "defines.h"
  72. #include "com.h"
  73. #include "xfer.h"
  74. #include "zmodem.h"
  75. #include "keybd.h"
  76. #include "sbuf.h"
  77. #include "sched.h"
  78. #include "externs.h"
  79. #include "prototyp.h"
  80.  
  81.  
  82.  
  83. void Find_Char (int);
  84. int Header_in_data (unsigned char *);
  85. void Send_ACK (XMARGSP);
  86. void Send_NAK (XMARGSP);
  87. static long Open_Xmodem_File (XMARGSP);
  88.  
  89. int XRInit (XMARGSP, int);
  90. int XREnd (XMARGSP, int);
  91. int XRRecInit (XMARGSP);
  92. int XRBrecInit (XMARGSP);
  93. int XRRecStart (XMARGSP);
  94. int XRWaitFirst (XMARGSP);
  95. int XRWaitBlock (XMARGSP);
  96. int XRRestart (XMARGSP);
  97. int XRSetOvrdr (XMARGSP);
  98.  
  99. STATES Xmodem_Receiver[] = {
  100.    { "XRInit",  XRInit },
  101.    { "XREnd",  XREnd },
  102.    { "XR0",  XRRecInit },
  103.    { "XR0B", XRBrecInit },
  104.    { "XR1",  XRRecStart },
  105.    { "XR2",  XRWaitFirst },
  106.    { "XR3",  XRWaitBlock },
  107.    { "XR4",  XRRestart },
  108.    { "XR5",  XRSetOvrdr }
  109. };
  110.  
  111. static long Open_Xmodem_File (args)
  112. XMARGSP args;
  113. {
  114.    char *s1, *s2;
  115.  
  116.    if (args->file_pointer == NULL)
  117.       {
  118.       args->temp_name = calloc (1, 80);
  119.  
  120.       if (args->path != NULL)
  121.          (void) strcpy (args->temp_name, args->path);
  122.  
  123.       s1 = &(args->temp_name[strlen (args->temp_name)]);
  124.       (void) strcpy (s1, "BTXXXXXX");
  125.       s2 = mktemp (args->temp_name);
  126.       if ((s2 == NULL) || ((args->file_pointer = buff_fopen (s2, "wb")) == NULL))
  127.          {
  128.          status_line (msgtxt[M_TEMP_NOT_OPEN], s2);
  129.          return (-1L);
  130.          }
  131.       }
  132.  
  133.    throughput (0, 0L);
  134.    return (0L);
  135. }
  136.  
  137. long Set_Up_Restart (args)
  138. XMARGSP args;
  139. {
  140.     char foo[100];
  141.     char foo1[50];
  142.    struct stat st;
  143.  
  144.    args->sub_results = 0;
  145.  
  146.    /* Look for file in directory */
  147.     if (args->path != NULL)
  148.         strcpy (foo, args->path);
  149.  
  150.     if ((args->received_name != NULL) &&
  151.        (strlen (args->received_name) > 0) &&
  152.         args->options.Resync)
  153.         {
  154.         strcat (foo, args->received_name);
  155.  
  156.       if (stat (foo, &st) == 0)
  157.          {
  158.          if ((st.st_size == args->filelen) && (st.st_atime == args->save_filetime.oneword.timedate))
  159.             {
  160.             if ((args->file_pointer = buff_fopen (foo, "rb+")) != NULL)
  161.                {
  162.                 throughput (0, 0L);
  163.                 fseek (args->file_pointer, 0L, SEEK_END);
  164.                 args->sub_results = DID_RESYNC;
  165.                 args->temp_name = calloc (1, 80);
  166.                 strcpy (args->temp_name, foo);
  167.                 args->prev_bytes = args->filelen;
  168.                 status_line (msgtxt[M_ALREADY_HAVE], foo);
  169.                 status_line (msgtxt[M_SYNCHRONIZING_EOF]);
  170.                 return (args->total_blocks + 1L);
  171.                     }
  172.             }
  173.          }
  174.  
  175.        /* Look for file in .Z file */
  176.        if (dexists (Abortlog_name))
  177.             {
  178.              sprintf (Resume_info, "%ld %lo", args->filelen, args->save_filetime.oneword.timedate);
  179.             if (check_failed (Abortlog_name, args->received_name, Resume_info, foo1))
  180.                 {
  181.                 foo[0] = '\0';
  182.                 /* Here it looks like it was a failed WaZOO session */
  183.                 if (args->path != NULL)
  184.                     strcpy (foo, args->path);
  185.                 strcat (foo, foo1);
  186.  
  187.             if ((args->file_pointer = buff_fopen (foo, "rb+")) != NULL)
  188.                   {
  189.                     stat (foo, &st);
  190.                 throughput (0, 0L);
  191.                    args->temp_name = calloc (1, 80);
  192.                    strcpy (args->temp_name, foo);
  193.                 args->prev_bytes = (st.st_size / 128L) * 128L;
  194.                    fseek (args->file_pointer, args->prev_bytes, SEEK_SET);
  195.                   status_line (msgtxt[M_SYNCHRONIZING_OFFSET], args->prev_bytes);
  196.                    return (args->prev_bytes / 128L + 1L);
  197.                     }
  198.                 }
  199.             }
  200.       }
  201.  
  202.     return (Open_Xmodem_File (args));
  203. }
  204.  
  205. void Finish_Xmodem_Receive (args)
  206. XMARGSP args;
  207. {
  208.    struct stat st;
  209.    char new_name[80];
  210.    struct utimbuf times;
  211.    int i, j, k;
  212.  
  213.    /* Set the file's time and date stamp */
  214.    if ((args->save_header == SOH) || (args->save_header == SYN))
  215.       {
  216.       (void) buff_fclose (args->file_pointer);
  217.       times.modtime = (long) args->save_filetime.oneword.timedate;
  218.       times.actime = (long) args->save_filetime.oneword.timedate;
  219.       (void) utime (args->temp_name, ×);
  220.       }
  221.    else
  222.       {
  223.       (void) strcpy (args->received_name, "");
  224.       (void) buff_fclose (args->file_pointer);
  225.       }
  226.  
  227.    if (args->result == SUCCESS)
  228.       {
  229.       /* Get the file information */
  230.       (void) stat (args->temp_name, &st);
  231.  
  232.       throughput (1, (unsigned long) (st.st_size - args->prev_bytes));
  233.  
  234.       update_files (0);
  235.  
  236.       if (args->sub_results & DID_RESYNC)
  237.          {
  238.          status_line ("%s: %s", msgtxt[M_FILE_RECEIVED], args->temp_name);
  239.          }
  240.       else
  241.          {
  242.          new_name[0] = '\0';
  243.          if (args->path != NULL)
  244.             (void) strcpy (new_name, args->path);
  245.          if ((args->filename == NULL) || (strlen (args->filename) == 0))
  246.             {
  247.             if (strlen (args->received_name) > 0)
  248.                (void) strcat (new_name, args->received_name);
  249.             else
  250.                (void) strcat (new_name, "BAD_FILE.000");
  251.             }
  252.          else
  253.             {
  254.             (void) strcat (new_name, args->filename);
  255.             }
  256.  
  257.          i = (int) strlen (args->temp_name) - 1;
  258.          j = (int) strlen (new_name) - 1;
  259.  
  260.          if (args->temp_name[i] == '.')
  261.             args->temp_name[i] = '\0';
  262.          if (new_name[j] == '.')
  263.             {
  264.             new_name[j] = '\0';
  265.             --j;
  266.             }
  267.  
  268.          i = 0;
  269.          k = is_arcmail (new_name, j);
  270.          status_line ("%s: %s", msgtxt[M_FILE_RECEIVED], new_name);
  271.          if ((!overwrite) || k)
  272.             {
  273.             while (rename (args->temp_name, new_name))
  274.                {
  275.                if (isdigit (new_name[j]))
  276.                   new_name[j]++;
  277.                else new_name[j] = '0';
  278.                if (!isdigit (new_name[j]))
  279.                   {
  280.                   return;
  281.                   }
  282.                i = 1;
  283.                }
  284.             CLEAR_IOERR ();
  285.             }
  286.          else
  287.             {
  288.             (void) unlink (new_name);
  289.             while (rename (args->temp_name, new_name))
  290.                {
  291.                if (!i)
  292.                   {
  293.                   status_line (msgtxt[M_ORIGINAL_NAME_BAD], new_name);
  294.                   }
  295.                if (isdigit (new_name[j]))
  296.                   new_name[j]++;
  297.                else new_name[j] = '0';
  298.                if (!isdigit (new_name[j]))
  299.                   {
  300.                   return;
  301.                   }
  302.                i = 1;
  303.                }
  304.             CLEAR_IOERR ();
  305.             }
  306.          if (i)
  307.             {
  308.             if (locate_y && !(fullscreen && un_attended))
  309.                gotoxy (2, locate_y - 1);
  310.             status_line (msgtxt[M_RENAME_MSG], new_name);
  311.             }
  312.          }
  313.  
  314.         remove_abort (Abortlog_name, args->received_name);
  315.       }
  316.    else
  317.       {
  318.         if ((args->received_name != NULL) && (strlen (args->received_name) > 0) && (args->save_header != 0))
  319.             {
  320.             sprintf (Resume_info, "%ld %lo", args->filelen, args->save_filetime.oneword.timedate);
  321.             add_abort (Abortlog_name, args->received_name, args->temp_name, args->path, Resume_info);
  322.             }
  323.         else
  324.             {
  325.           /* File aborted, so remove all traces of it */
  326.           if (args->temp_name != NULL)
  327.              (void) unlink (args->temp_name);
  328.             }
  329.       }
  330.  
  331.    if (args->temp_name != NULL)
  332.       free (args->temp_name);
  333. }
  334.  
  335. void Get_Telink_Info (args)
  336. XMARGSP args;
  337. {
  338.    char *p1;
  339.    char junkbuff[100];
  340.    TLDATAP t;
  341.     unsigned int i, j;
  342.  
  343.    /* Figure out how many blocks we will get */
  344.    t = (TLDATAP) &(args->header);
  345.    args->total_blocks = (t->filelength + 127)/ 128;
  346.    t->nullbyte = '\0';
  347.    p1 = strchr (t->filename, ' ');
  348.    if (p1 != NULL)
  349.       *p1 = '\0';
  350.    strcpy (args->received_name, t->filename);
  351.    args->save_header = args->header;
  352.    if (args->save_header == SYN)
  353.       {
  354.       i = t->filetime.twowords.time;
  355.       j = t->filetime.twowords.date;
  356.       args->save_filetime.oneword.timedate = _dtoxtime (j >> 9, (j >> 5) & 0x0f,
  357.          j & 0x1f, i >> 11, (i >> 5) & 0x3f, i & 0x1f);
  358.       }
  359.    else
  360.       {
  361.       args->save_filetime.oneword.timedate = t->filetime.oneword.timedate;
  362.       }
  363.    args->filelen = t->filelength;
  364.    (void) sprintf (junkbuff, msgtxt[M_RECEIVE_MSG],
  365.       args->total_blocks, t->filename, t->sendingprog, t->filelength);
  366.  
  367.     strcpy (sending_program, t->sendingprog);
  368.    if (un_attended && fullscreen)
  369.       {
  370.       clear_filetransfer ();
  371.       sb_move (filewin, 1, 2);
  372.       sb_puts (filewin, (unsigned char *) junkbuff);
  373.       elapse_time ();
  374.       sb_show ();
  375.       }
  376.    else
  377.       {
  378.       status_line ("+%s", junkbuff);
  379.       printf ("\n");
  380.       locate_y = wherey ();
  381.       locate_x = wherex ();
  382.       }
  383.    }
  384.  
  385. int Read_Block (args)
  386. XMARGSP args;
  387. {
  388.    unsigned char *p; /* Pointers to XMODEM data */
  389.    int i;            /* Counter */
  390.    int j;            /* Counter start */
  391.    unsigned char c;  /* character being processed */
  392.    int in_char;
  393.    char junkbuff[128];
  394.    long head_timer;
  395.  
  396.    if (got_ESC ())
  397.       {
  398.       status_line (msgtxt[M_KBD_MSG]);
  399.       return (KBD_ERR);
  400.       }
  401.  
  402.    /* Set up to point into the XMODEM data structure */
  403.    p = (unsigned char *) &(args->header);
  404.  
  405.    /* Get the first character that is waiting */
  406.    *p = (unsigned char) TIMED_READ (8);
  407.  
  408.    head_timer = timerset (6000);
  409.    j = 1;
  410.    while (!timeup (head_timer))
  411.       {
  412.       /* Now key off of the header character */
  413.       switch (*p)
  414.          {
  415.          case EOT:   /* End of file */
  416.             /* Is this a valid EOT */
  417.             if (args->total_blocks <= args->WriteBLK)
  418.                {
  419.                return (EOT_BLOCK);
  420.                }
  421.             else
  422.                {
  423.                status_line (msgtxt[M_UNEXPECTED_EOF], args->total_blocks);
  424.                return (BAD_BLOCK);
  425.                }
  426.  
  427.          case SYN:   /* Telink block */
  428.             /* For Telink, read all of the data except the checksum */
  429.             for (i = 1; i < sizeof (TLDATA) - 2; i++)
  430.                {
  431.                /* If we go more than 5 second, then we have a short block */
  432.                if ((in_char = TIMED_READ (5)) < 0)
  433.                   {
  434.                   return (BAD_BLOCK);
  435.                   }
  436.                *(++p) = (unsigned char) (in_char & 0xff);
  437.                }
  438.  
  439.             /* if the block number or its complement are wrong, return error */
  440.             if ((args->block_num != 0) || (args->block_num_comp != 0xff))
  441.                {
  442.                return (BAD_BLOCK);
  443.                }
  444.  
  445.             /* Now calculate the checksum - Telink block always checksum mode */
  446.             Data_Check ((XMDATAP) &(args->header), CHECKSUM);
  447.  
  448.             /* See if we can receive the checksum byte */
  449.             if ((in_char = TIMED_READ (10)) < 0)
  450.                {
  451.                Xmodem_Error (msgtxt[M_TIMEOUT], 0L);
  452.                return (BAD_BLOCK);
  453.                }
  454.  
  455.             /* Was it right */
  456.             c = (unsigned char) (in_char & 0xff);
  457.             if (c != args->data_check[0])
  458.                {
  459.                Xmodem_Error (msgtxt[M_CHECKSUM], 0L);
  460.                return (BAD_BLOCK);
  461.                }
  462.             /* Everything looks good, it must be a legal TELINK block */
  463.  
  464.             Get_Telink_Info (args);
  465.             return (TELINK_BLOCK);
  466.  
  467.          case SOH:   /* Normal data block */
  468.             args->datalen = 128;
  469.             /* Read in all of the data for an XMODEM block except the checksum */
  470.             p += (j - 1);
  471.             for (i = j; i < sizeof (XMDATA) - 2; i++)
  472.                {
  473.                /* If we go more than 5 seconds, then it is a short block */
  474.                if ((in_char = TIMED_READ (5)) < 0)
  475.                   {
  476.                   return (BAD_BLOCK);
  477.                   }
  478.                *(++p) = (unsigned char) (in_char & 0xff);
  479.                }
  480.  
  481.             /* The block number is 0 to 255 inclusive */
  482.             c = (unsigned char) (args->blocknum & 0xff);
  483.  
  484.             /* Properly calculate the CRC or checksum */
  485.             Data_Check ((XMDATAP) &(args->header), args->options.do_CRC ? CRC : CHECKSUM);
  486.  
  487.             /* Can we get the checksum byte */
  488.             if ((in_char = TIMED_READ (10)) < 0)
  489.                {
  490.                Xmodem_Error (msgtxt[M_TIMEOUT], args->WriteBLK);
  491.                return (BAD_BLOCK);
  492.                }
  493.  
  494.             /* Is it the right value */
  495.             c = (unsigned char) (in_char & 0xff);
  496.             if (c != args->data_check[0])
  497.                {
  498.                status_line (">Xmodem Receive: Bad %s", (args->options.do_CRC)?"CRC":"checksum");
  499.                Xmodem_Error (msgtxt[M_CRC_MSG], args->WriteBLK);
  500.                if (args->options.do_CRC)
  501.                   (void) TIMED_READ (5);
  502.                return (BAD_BLOCK);
  503.                }
  504.  
  505.             /* If we are in CRC mode, do the second byte */
  506.             if (args->options.do_CRC)
  507.                {
  508.                /* Can we get the character */
  509.                if ((in_char = TIMED_READ (10)) < 0)
  510.                   {
  511.                   status_line (">Xmodem Receive: Timeout waiting for CRC byte 2");
  512.                   Xmodem_Error (msgtxt[M_TIMEOUT], args->WriteBLK);
  513.                   return (BAD_BLOCK);
  514.                   }
  515.                /* Is it right */
  516.                c = (unsigned char) (in_char & 0xff);
  517.                if (c != args->data_check[1])
  518.                   {
  519.                   Xmodem_Error (msgtxt[M_CRC_MSG], args->WriteBLK);
  520.                   return (BAD_BLOCK);
  521.                   }
  522.                }
  523.  
  524.             /* Do we have a valid data block */
  525.             if (args->block_num_comp != ((~(args->block_num)) & 0xff))
  526.                {
  527.                if (!(args->options.SEAlink))
  528.                   {
  529.                   Xmodem_Error (msgtxt[M_JUNK_BLOCK], args->WriteBLK);
  530.                   return (BAD_BLOCK);
  531.                   }
  532.  
  533.                p = (unsigned char *) &(args->header);
  534.                j = Header_in_data (p);
  535.                if (j)
  536.                   {
  537.                   continue;
  538.                   }
  539.  
  540.                j = 1;
  541.                Find_Char (SOH);
  542.                *p = (unsigned char) TIMED_READ (0);
  543.                }
  544.  
  545.             if ((args->WriteBLK == 1) && (args->header == SOH) && (args->block_num == 0))
  546.                {
  547.                Get_Telink_Info (args);
  548.                return (SEALINK_BLOCK);
  549.                }
  550.  
  551.             if (first_block)
  552.                {
  553.                struct _pkthdr *packet;
  554.  
  555.                packet = (struct _pkthdr *) args->data;
  556.                if (!remote_capabilities)
  557.                   {
  558.                   remote_addr.Zone = packet->orig_zone;
  559.                   remote_addr.Net = packet->orig_net;
  560.                   remote_addr.Node = packet->orig_node;
  561.                   if (packet->rate == 2)
  562.                      {
  563.                      /* This is a special type 2.2 packet! */
  564.                      remote_addr.Point = (unsigned) packet->year;
  565.  
  566.                      packet->B_fill3 = 0L;
  567.                      packet->B_fill2[8] = '\0';
  568.                      remote_addr.Domain = find_domain (packet->B_fill2);
  569.                      if ((pvtnet >= 0) &&
  570.                          ((remote_addr.Zone == alias[assumed].Zone) || (remote_addr.Zone == 0)) &&
  571.                          (remote_addr.Net == boss_addr.Net) && (remote_addr.Node == boss_addr.Node) &&
  572.                          (remote_addr.Point > 0))
  573.                         {
  574.                         remote_addr.Net = pvtnet;
  575.                         remote_addr.Node = remote_addr.Point;
  576.                         remote_addr.Point = 0;
  577.                         }
  578.                      else if (remote_addr.Point > 0)
  579.                         {
  580.                         remote_addr.Point = 0;
  581.                         remote_addr.Node = -1;
  582.                         }
  583.                      }
  584.                   else
  585.                      {
  586.                      remote_addr.Point = 0;
  587.                      remote_addr.Domain = NULL;
  588.                      }
  589.                   }
  590.                if (who_is_he)
  591.                   {
  592.                   if (!remote_addr.Zone && !remote_addr.Net && !remote_addr.Node)
  593.                      {
  594.                      DTR_OFF ();                   /* Bad trip, cut it off */
  595.                      timer (2);                    /* Wait two secs        */
  596.                      return(CARRIER_ERR);          /* Get out of here!     */
  597.                      }
  598.  
  599.                   if (nodefind (&remote_addr, 1))
  600.                      {
  601.                      if (!remote_addr.Zone)
  602.                         remote_addr.Zone = found_zone;
  603.  
  604.                      (void) sprintf (junkbuff, "%s: %s (%s)",
  605.                               msgtxt[M_REMOTE_SYSTEM],
  606.                               newnodedes.SystemName,
  607.                               Full_Addr_Str (&remote_addr));
  608.                      }
  609.                   else
  610.                      {
  611.                      (void) sprintf (junkbuff, "%s: %s (%s)",
  612.                               msgtxt[M_REMOTE_SYSTEM],
  613.                               msgtxt[M_UNKNOWN_MAILER],
  614.                               Full_Addr_Str (&remote_addr));
  615.                      }
  616.  
  617.                   last_type (2, &remote_addr);
  618.                   status_line (junkbuff);
  619.                   }
  620.                     if (sending_program[0] != '\0')
  621.                         {
  622.                      status_line ("%s %s", msgtxt[M_REMOTE_USES], sending_program);
  623.                         }
  624.                     else
  625.                         {
  626.                   log_product (packet->product, 0, packet->serial);
  627.                         }
  628.                who_is_he = 0;
  629.                first_block = 0;
  630.                }
  631.  
  632.             if (args->WriteBLK == args->total_blocks)
  633.                {
  634.                args->datalen = (int) (args->filelen - ((args->WriteBLK - 1) * 128));
  635.                }
  636.  
  637.             /* If we got this far, it is a valid data block */
  638.             args->recblock = args->block_num;
  639.             return (XMODEM_BLOCK);
  640.  
  641.          default:    /* Bad block */
  642.             if ((args->blocknum <= 1) || (PEEKBYTE () < 0))
  643.                return (BAD_BLOCK);
  644.  
  645.             /* Garbage header, return bad */
  646.             *p = (unsigned char) TIMED_READ (0);
  647.          }
  648.       }
  649.    return (BAD_BLOCK);
  650. }
  651.  
  652. int XRInit (args, start_state)
  653. XMARGSP args;
  654. int start_state;
  655. {
  656.     char *HoldName;
  657.  
  658.    args->tries = 0;
  659.    args->goodfile = 1;
  660.    XON_DISABLE ();
  661.    HoldName = HoldAreaNameMunge(&called_addr);
  662.    sprintf (Abortlog_name, "%s%s.Z\0",
  663.       HoldName, Hex_Addr_Str (&remote_addr));
  664.     sending_program[0] = '\0';
  665.    return (start_state);
  666. }
  667.  
  668. int XREnd (args, cur_state)
  669. XMARGSP args;
  670. int cur_state;
  671. {
  672.    args->result = cur_state;
  673.  
  674.    Finish_Xmodem_Receive (args);
  675.  
  676.    return (cur_state);
  677. }
  678.  
  679. int XRRecInit (args)
  680. XMARGSP args;
  681. {
  682.    args->options.SEAlink = 0;
  683.    args->options.SLO = 0;
  684.    args->options.Resync = 0;
  685.    args->options.MacFlow = 0;
  686.    args->options.do_CRC = 1;
  687.    args->blocknum = 0;
  688.    args->WriteBLK = 1;
  689.    args->curr_byte = 0L;
  690.    args->tries = 0;
  691.    return (XR1);
  692. }
  693.  
  694. int XRBrecInit (args)
  695. XMARGSP args;
  696. {
  697.    args->options.SEAlink = 0;
  698.    args->options.SLO = 0;
  699.    args->options.Resync = 0;
  700.    args->options.MacFlow = 0;
  701.    args->options.do_CRC = 1;
  702.    args->blocknum = 0;
  703.    args->WriteBLK = 1;
  704.    args->curr_byte = 0L;
  705.    args->tries = 0;
  706.    return (XR2);
  707. }
  708.  
  709. int XRRecStart (args)
  710. XMARGSP args;
  711. {
  712.    Send_NAK (args);
  713.    return (XR2);
  714. }
  715.  
  716. int XRWaitFirst (args)
  717. XMARGSP args;
  718. {
  719.    long XR2Timer;
  720.  
  721.    XR2Timer = timerset (800);
  722.    if (args->tries >= 10)
  723.       {
  724.       args->goodfile = 0;
  725.       return (TIME_ERR);
  726.       }
  727.    if (args->tries == 5)
  728.       {
  729.       args->options.do_CRC = 0;
  730.       ++(args->tries);
  731.       return (XR1);
  732.       }
  733.  
  734.    while (CARRIER)
  735.       {
  736.       switch (Read_Block (args))
  737.          {
  738.          case EOT_BLOCK:
  739.                 args->WriteBLK = 0;
  740.             Send_ACK (args);
  741.             return (SUCCESS_EOT);
  742.  
  743.          case TELINK_BLOCK:
  744.             if (Open_Xmodem_File (args) == -1L)
  745.                return (OPEN_ERR);
  746.             Send_ACK (args);
  747.             args->tries = 0;
  748.             return (XR3);
  749.  
  750.          case SEALINK_BLOCK:
  751.             args->options.SEAlink = no_sealink ? 0 : 1;
  752.             if (args->options.SEAlink && !no_resync)
  753.                args->options.Resync = (((SEADATAP) (&(args->header)))->Resync) != 0;
  754.             return (XR4);
  755.  
  756.          case XMODEM_BLOCK:
  757.             if (args->recblock == 1)
  758.                {
  759.                if (Open_Xmodem_File (args) == -1L)
  760.                   return (OPEN_ERR);
  761.                (void) buff_fwrite (args->data, sizeof (unsigned char), args->datalen, args->file_pointer);
  762.                ++(args->WriteBLK);
  763.                args->curr_byte = 128L;
  764.                ++(args->blocknum);
  765.                Send_ACK (args);
  766.                args->tries = 0;
  767.                return (XR3);
  768.                }
  769.  
  770.             /* Fallthrough on wrong block */
  771.  
  772.          case BAD_BLOCK:
  773.             ++(args->tries);
  774.             return (XR1);
  775.  
  776.          case CARRIER_ERR:
  777.          case KBD_ERR:
  778.             return (CARRIER_ERR);
  779.          }
  780.  
  781.       if (timeup (XR2Timer))
  782.          {
  783.          ++(args->tries);
  784.          return (XR1);
  785.          }
  786.       }
  787.  
  788.    return (CARRIER_ERR);
  789. }
  790.  
  791. int XRWaitBlock (args)
  792. XMARGSP args;
  793. {
  794.    if (args->tries >= 10)
  795.       {
  796.       args->goodfile = 0;
  797.       return (TIME_ERR);
  798.       }
  799.  
  800.    while (CARRIER)
  801.       {
  802.       switch (Read_Block (args))
  803.          {
  804.          case EOT_BLOCK:
  805.             args->options.SLO = 0;
  806.             Send_ACK (args);
  807.             return (SUCCESS);
  808.  
  809.          case XMODEM_BLOCK:
  810.             if (args->recblock == (unsigned char) ((args->blocknum - 1) & 0xff))
  811.                {
  812.                --(args->blocknum);
  813.                Send_ACK (args);
  814.                return (XR3);
  815.                }
  816.  
  817.             if (args->recblock == args->blocknum)
  818.                {
  819.                (void) buff_fwrite (args->data, sizeof (unsigned char), args->datalen, args->file_pointer);
  820.                ++(args->WriteBLK);
  821.                args->curr_byte += 128L;
  822.                Send_ACK (args);
  823.                args->tries = 0;
  824.                return (XR3);
  825.                }
  826.  
  827.             if (args->recblock < args->blocknum)
  828.                {
  829.                args->recblock += 256;
  830.                }
  831.  
  832.             if ((args->recblock > (unsigned) args->blocknum) && (args->recblock <= ((unsigned) (((unsigned) args->blocknum) + 127))))
  833.                {
  834.                     if (args->tries != 0)
  835.                         {
  836.                         /* We have sent at least one nak, now only send them
  837.                             every so often to allow buffers to drain */
  838.                         if ((args->recblock - (unsigned) args->blocknum) % 16)
  839.                             return (XR3);
  840.  
  841.                         /* If it is a multiple of 16, then check that it is
  842.                             higher than 32 */
  843.                         if ((args->recblock - (unsigned) args->blocknum) / 16 < 2)
  844.                             return (XR3);
  845.                         }
  846.                }
  847.  
  848.             /* fallthrough on bad block */
  849.  
  850.          case BAD_BLOCK:
  851.             Send_NAK (args);
  852.             ++(args->tries);
  853.             return (XR3);
  854.  
  855.          case CARRIER_ERR:
  856.          case KBD_ERR:
  857.             return (CARRIER_ERR);
  858.          }
  859.       }
  860.  
  861.    return (CARRIER_ERR);
  862. }
  863.  
  864. int XRRestart (args)
  865. XMARGSP args;
  866. {
  867.    long c;
  868.  
  869.    c = Set_Up_Restart (args);
  870.    if (c == -1L)
  871.       return (OPEN_ERR);
  872.  
  873.    if ((!c) || (!(args->options.Resync)))
  874.       {
  875.       Send_ACK (args);
  876.       args->tries = 0;
  877.       }
  878.    else
  879.       {
  880.       args->WriteBLK = c;
  881.       args->curr_byte = (c - 1) * 128L;
  882.       args->blocknum = (unsigned char) ((args->WriteBLK) & 0xff);
  883.       Send_NAK (args);
  884.       }
  885.  
  886.    return (XR5);
  887. }
  888.  
  889. int XRSetOvrdr (args)
  890. XMARGSP args;
  891. {
  892.    if (!no_overdrive)
  893.       args->options.SLO = (((SEADATAP) (&(args->header)))->SLO) != 0;
  894.  
  895.     if (args->options.SLO)
  896.         show_block ((long) (args->WriteBLK - 1), " *Overdrive*", args);
  897.  
  898.    return (XR3);
  899. }
  900.  
  901. int Xmodem_Receive_File (path, filename)
  902. char *path;
  903. char *filename;
  904. {
  905.    XMARGS xmfile;
  906.    int res;
  907.  
  908.    locate_y = wherey ();
  909.    locate_x = wherex ();
  910.    memset (&xmfile, 0, sizeof (XMARGS));
  911.    xmfile.path = path;
  912.    xmfile.filename = filename;
  913.    xmfile.total_blocks = -1L;
  914.    xmfile.sent_ACK = 0;
  915.    res = state_machine (Xmodem_Receiver, &xmfile, XR0);
  916.    return (res);
  917. }
  918.  
  919. int Batch_Xmodem_Receive_File (path, filename)
  920. char *path;
  921. char *filename;
  922. {
  923.    XMARGS xmfile;
  924.    int res;
  925.  
  926.    locate_y = wherey ();
  927.    locate_x = wherex ();
  928.    memset (&xmfile, 0, sizeof (XMARGS));
  929.    xmfile.path = path;
  930.    xmfile.filename = filename;
  931.    xmfile.total_blocks = -1L;
  932.    xmfile.sent_ACK = 0;
  933.    res = state_machine (Xmodem_Receiver, &xmfile, XR0B);
  934.    return (res);
  935. }
  936.  
  937. int SAInit (XMARGSP, int);
  938. int SAEnd (XMARGSP, int);
  939. int SAClearLine (XMARGSP);
  940. int SASendACK (XMARGSP);
  941. int SASEAlink (XMARGSP);
  942. int SAIncBlk (XMARGSP);
  943.  
  944. STATES ACK_States[] = {
  945.    { "SAInit",  SAInit },
  946.    { "SAEnd",  SAEnd },
  947.    { "SA0",  SAClearLine },
  948.    { "SA1",  SASendACK },
  949.    { "SA2",  SASEAlink },
  950.    { "SA3",  SAIncBlk }
  951. };
  952.  
  953. int SAInit (args, start_state)
  954. XMARGSP args;
  955. int start_state;
  956. {
  957.    return (start_state);
  958.    args;
  959. }
  960.  
  961. int SAEnd (args, cur_state)
  962. XMARGSP args;
  963. int cur_state;
  964. {
  965.    return (cur_state);
  966.    args;
  967. }
  968.  
  969. int SAClearLine (args)
  970. XMARGSP args;
  971. {
  972.    long SA0Timer;
  973.  
  974.    SA0Timer = timerset (3000);
  975.    if (args->options.SLO)
  976.       return (SA3);
  977.  
  978.    if (args->options.SEAlink)
  979.       return (SA1);
  980.  
  981.    while (CARRIER && !timeup (SA0Timer))
  982.       {
  983.       if (PEEKBYTE () >= 0)
  984.          {
  985.          (void) TIMED_READ (0);
  986.          time_release ();
  987.          continue;
  988.          }
  989.  
  990.       return (SA1);
  991.       }
  992.  
  993.    return (TIME_ERR);
  994. }
  995.  
  996. int SASendACK (args)
  997. XMARGSP args;
  998. {
  999.    SENDBYTE (ACK);
  1000.    args->sent_ACK = 1;
  1001.    return (SA2);
  1002. }
  1003.  
  1004. int SASEAlink (args)
  1005. XMARGSP args;
  1006. {
  1007.    if (!(args->options.SEAlink))
  1008.       return (SA3);
  1009.  
  1010.    SENDBYTE (args->blocknum);
  1011.    SENDBYTE (~(args->blocknum));
  1012.    return (SA3);
  1013. }
  1014.  
  1015. void show_block (b, c, args)
  1016. long b;
  1017. char *c;
  1018. XMARGSP args;
  1019. {
  1020.    char j[100];
  1021.    int i;
  1022.    long k;
  1023.  
  1024.    if (fullscreen && un_attended)
  1025.       {
  1026.        elapse_time();
  1027.       sb_move (filewin, 2, 2);
  1028.       sb_puts (filewin, (unsigned char *) ultoa (((unsigned long) b), e_input, 10));
  1029.         if (c)
  1030.           (void) sb_puts (filewin, c);
  1031.  
  1032.       k = args->filelen - args->curr_byte;
  1033.       if (k < 0L)
  1034.          k = 0L;
  1035.  
  1036.         if (lock_baud)            /* CML correctly calculating send/receive time */
  1037.             i = (int) ((k * 10 / actual_baud * 100 / ((args->save_header == SOH) ? 94 : 70) + 59) / 60);
  1038.         else 
  1039.             i = (int) ((k * 10 / cur_baud * 100 / ((args->save_header == SOH) ? 94 : 70) + 59) / 60);
  1040.       sprintf (j, "%3d min", i);
  1041.  
  1042.       sb_move (filewin, 2, 69);
  1043.       sb_puts (filewin, j);
  1044.       sb_show ();
  1045.       }
  1046.    else
  1047.       {
  1048.       gotoxy (locate_x, locate_y);
  1049.       (void) printf ("%s", ultoa (((unsigned long) b), e_input, 10));
  1050.         if (c)
  1051.             (void) printf ("%s", c);
  1052.       }
  1053. }
  1054.  
  1055. int SAIncBlk (args)
  1056. XMARGSP args;
  1057. {
  1058.    ++(args->blocknum);
  1059.    if ((args->options.SLO) &&
  1060.         (((args->WriteBLK > 0) && (!((args->WriteBLK - 1) & 0x001F)) && (args->WriteBLK < args->total_blocks)) ||
  1061.       (args->WriteBLK >= args->total_blocks)))
  1062.       {
  1063.         show_block ((long) (args->WriteBLK - 1), " *Overdrive*", args);
  1064.       }
  1065.     else if ((!(args->options.SLO)) && (args->WriteBLK > 0))
  1066.       {
  1067.         show_block ((long) (args->WriteBLK - 1), NULL, args);
  1068.       }
  1069.  
  1070.    return (SUCCESS);
  1071. }
  1072.  
  1073. void Send_ACK (args)
  1074. XMARGSP args;
  1075. {
  1076.    state_machine (ACK_States, args, SA0);
  1077. }
  1078.  
  1079. void Send_Resync_Packet (XMARGSP);
  1080.  
  1081. int SNInit (XMARGSP, int);
  1082. int SNEnd (XMARGSP, int);
  1083. int SNClearLine (XMARGSP);
  1084. int SNSendNAK (XMARGSP);
  1085. int SNSEAlink (XMARGSP);
  1086. int SNAckResync (XMARGSP);
  1087.  
  1088. STATES NAK_States[] = {
  1089.    { "SNInit",  SNInit },
  1090.    { "SNEnd",  SNEnd },
  1091.    { "SN0",  SNClearLine },
  1092.    { "SN1",  SNSendNAK },
  1093.    { "SN2",  SNSEAlink },
  1094.    { "SN3",  SNAckResync }
  1095. };
  1096.  
  1097. int SNInit (args, start_state)
  1098. XMARGSP args;
  1099. int start_state;
  1100. {
  1101.    return (start_state);
  1102.    args;
  1103. }
  1104.  
  1105. int SNEnd (args, cur_state)
  1106. XMARGSP args;
  1107. int cur_state;
  1108. {
  1109.    return (cur_state);
  1110.    args;
  1111. }
  1112.  
  1113. int SNClearLine (args)
  1114. XMARGSP args;
  1115. {
  1116.    long SN0Timer;
  1117.  
  1118.    SN0Timer = timerset (3000);
  1119.    if (args->options.Resync)
  1120.       {
  1121.       Send_Resync_Packet (args);
  1122.       return (SN3);
  1123.       }
  1124.  
  1125.    if (args->options.SEAlink)
  1126.       return (SN1);
  1127.  
  1128.    while (CARRIER && !timeup (SN0Timer))
  1129.       {
  1130.       if (PEEKBYTE () >= 0)
  1131.          {
  1132.          (void) TIMED_READ (0);
  1133.          time_release ();
  1134.          continue;
  1135.          }
  1136.  
  1137.       return (SN1);
  1138.       }
  1139.  
  1140.    return (TIME_ERR);
  1141. }
  1142.  
  1143. int SNSendNAK (args)
  1144. XMARGSP args;
  1145. {
  1146.    if (args->options.do_CRC && (args->sent_ACK == 0))
  1147.       SENDBYTE (WANTCRC);
  1148.    else
  1149.       SENDBYTE (NAK);
  1150.    return (SN2);
  1151. }
  1152.  
  1153. int SNSEAlink (args)
  1154. XMARGSP args;
  1155. {
  1156.    if (!(args->options.SEAlink))
  1157.       return (SUCCESS);
  1158.  
  1159.    SENDBYTE (args->blocknum);
  1160.    SENDBYTE (~(args->blocknum));
  1161.    return (SUCCESS);
  1162. }
  1163.  
  1164. int SNAckResync (args)
  1165. XMARGSP args;
  1166. {
  1167.    long SN3Timer;
  1168.    int c;
  1169.  
  1170.    SN3Timer = timerset (3000);
  1171.  
  1172.    while (CARRIER && !timeup (SN3Timer))
  1173.       {
  1174.       if ((c = TIMED_READ (10)) == 0xffff)
  1175.          {
  1176.          Send_Resync_Packet (args);
  1177.          continue;
  1178.          }
  1179.  
  1180.       if (c == ACK)
  1181.             {
  1182.             big_pause (1);
  1183.             c = PEEKBYTE();
  1184.             if ((c == SOH) || (c == EOT))
  1185.              return (SUCCESS);
  1186.             }
  1187. //        time_release();            /* CML -- stop hogging my CPU! */
  1188.       }
  1189.  
  1190.    if (!CARRIER)
  1191.       return (CARRIER_ERR);
  1192.    else
  1193.       return (TIME_ERR);
  1194. }
  1195.  
  1196. void Send_NAK (args)
  1197. XMARGSP args;
  1198. {
  1199.    state_machine (NAK_States, args, SN0);
  1200. }
  1201.  
  1202. void Send_Resync_Packet (args)
  1203. XMARGSP args;
  1204. {
  1205.    unsigned char resyncit[30];
  1206.    unsigned int nak_crc;
  1207.  
  1208.    SENDBYTE (SYN);
  1209.    (void) sprintf ((char *) resyncit, "%ld", args->WriteBLK);
  1210.    SENDCHARS ((char *) resyncit, strlen ((char *) resyncit), 1);
  1211.    nak_crc = crc_block ((unsigned char *) resyncit, (int) strlen ((char *) resyncit));
  1212.    SENDBYTE (ETX);
  1213.    SENDBYTE ((unsigned char) (nak_crc & 0xff));
  1214.    CLEAR_INBOUND ();
  1215.    SENDBYTE ((unsigned char) (nak_crc >> 8));
  1216. }
  1217.  
  1218. void Xmodem_Error (s, block_number)
  1219. char *s;
  1220. long block_number;
  1221. {
  1222.    char j[50];
  1223.    char k[50];
  1224.  
  1225.    (void) sprintf (j, "%s %s %ld", s, msgtxt[M_ON_BLOCK], block_number);
  1226.    (void) sprintf (k, "%-49.49s", j);
  1227.  
  1228.    status_line (">Xmodem Error: %s", k);
  1229.    if (fullscreen && un_attended)
  1230.       {
  1231.       sb_move (filewin, 2, 20);
  1232.       sb_puts (filewin, (unsigned char *) k);
  1233.       sb_show ();
  1234.       }
  1235.    else
  1236.       {
  1237.       gotoxy (locate_x + 20, locate_y);
  1238.       (void) cputs (k);
  1239.       }
  1240. }
  1241.  
  1242. void Find_Char (c)
  1243. int c;
  1244. {
  1245.    long t1;
  1246.    long t2;
  1247.  
  1248.    t1 = timerset (3000);
  1249.    t2 = timerset (100);
  1250.    while (!timeup (t1) && !timeup (t2))
  1251.       {
  1252.       if (!CARRIER)
  1253.          break;
  1254.  
  1255.       if (PEEKBYTE () == (c & 0xff))
  1256.          break;
  1257.       else if (PEEKBYTE () >= 0)
  1258.          {
  1259.          (void) TIMED_READ (0);
  1260.          t2 = timerset (100);
  1261.          }
  1262.  
  1263. //        time_release();            /* CML -- stop hogging my CPU! */
  1264.       }
  1265. }
  1266.  
  1267. int Header_in_data (p)
  1268. unsigned char *p;
  1269. {
  1270.    int i;
  1271.    int j;
  1272.    char *p1;
  1273.  
  1274.    p1 = (char *) p;
  1275.    ++p1;
  1276.    j = sizeof (XMDATA) - 2;
  1277.    for (i = 1; i < j; i++, p1++)
  1278.       {
  1279.       if (*p1 == SOH)
  1280.          {
  1281.          (void) memcpy (p, p1, (unsigned int) (j - i));
  1282.          return (j - i);
  1283.          }
  1284.       }
  1285.  
  1286.    return (0);
  1287. }
  1288.  
  1289. 
  1290.