home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / comm / zmax.zip / ZMAX.C < prev    next >
Text File  |  1990-08-16  |  60KB  |  1,752 lines

  1. /*
  2. LEGAL STUFF
  3. ------------------------------------------------------------------------------
  4.  
  5. The protocol, documentation, and Zmax.c routines are by Mike Bryeans.
  6.  
  7. Zmax  is  NOT public domain. Micro TECH Systems  Retains  ALL RIGHTS TO
  8. THIS PROTOCOL.
  9.  
  10. No  PART  of Zmax may be used in development  of  a  NON-ZMAX protocol.
  11.  
  12. Developers  are  granted  a  license  to  use  Zmax  in  NON-COMMERCIAL
  13. applications and environments ONLY.
  14.  
  15.               A 10 dollar donation is requested to help
  16.               offset development costs and to help with
  17.               the  salaries  of the  technical  support
  18.               person(s).
  19.  
  20. If  you application is intended for use in a program that  is to be sold
  21. commercially, including shareware, you must  apply for a Zmax COMMERCIAL
  22. License.
  23.  
  24. If  you  intend  to  develop  a Zmax  driver  for  USE  in  a commercial
  25. environment, you must apply for a Zmax  COMMERCIAL license.
  26.  
  27. All goverment agents Federal, State, and Local must apply for a Zmax
  28. COMMERICAL license.
  29.  
  30. You  may  NOT modify Zmax specifications.  Zmax  MUST  remain uniform and
  31. only Micro TECH Systems may issue NEW or IMPROVED Zmax specifications.
  32.  
  33. If you have a particular item in mind, submit it along with a modified
  34. Zmax.c (Using our Zmax.c driver code) to Micro  TECH Systems.
  35.  
  36.                          Micro TECH Systems
  37.                          555 North Spring, #39
  38.                          Cape Girardeau Mo. 63701
  39.  
  40.                          Data Number  1-314-334-6359
  41.  
  42.              Zmax  specifications, ver. 1.00
  43.  
  44. This is a full functional, tested, driver. I've attempted to keep
  45. the code as simple as possible and use terms that anyone thats
  46. written any type of protocol knows since its to be used as a guide
  47. to other implementations.
  48.  
  49. Zmax was designed with reliablity in mind as the FIRST and foremost
  50. concern, speed came in a close second. You'll no doubt notice a couple
  51. of areas where it could be speeded up and I was tempted. Zmax isn't
  52. the FASTEST protocol around, but then it wasn't suppose to be.
  53.  
  54. I wanted the best all round protocol which would always get the file
  55. there intact and as quickly as possible. I beleive you'll be very hard
  56. pressed to find any protocol that will best Zmax in RELIABLITY, FLEXABLITY,
  57. and SPEED.
  58.  
  59.  
  60. */
  61.  
  62. /* Include files */
  63.  
  64. #include<stdio.h>
  65. #include "zmax.h"
  66. #include<malloc.h>
  67. #include<filedata.h>
  68. #include<comm.h>
  69. #include<ctype.h>
  70.  
  71. /* Globle Declares */
  72. FILE *out;
  73. unsigned long UpdCrc32(char byte, unsigned long crc);
  74. long file_position,seof;
  75. int cancel,percent_size,total_errors = 0,endsend = 0,delete_aborted_transfers = 1;
  76. struct filedata filstruc;
  77. long locked_port, atol(), timerset(),amt_sent;
  78. char *Screen_ptr;
  79. char acks_required=0;
  80. char tbuf[2048],junk_string[81];
  81. int block_len,return_code = 1,port_ptr;
  82. unsigned cur_baud,connect_rate,sending_file;
  83. ASYNC *port;
  84. int     IOadrs = 0x3f8;                      /* comm port base I/O address */
  85. char    irqm = IRQ4;                         /* mask for selected IRQ line */
  86. char    vctrn = VCTR4;                        /* comm interrupt vector nbr */
  87. char log_file[81];
  88.  
  89. /* Zmax Structures */
  90.  
  91. struct Zhead                           /* File info data structure */
  92. {   long flen;                         /* file length */
  93.     unsigned fdate;                    /* Files DATE stamp, DOS format */
  94.     unsigned ftime;                    /* Files TIME stamp, DOS format */
  95.     char fnam[14];                     /* original file name */
  96. }   ;
  97.  
  98. struct _block_header
  99.   {
  100.    long position;
  101.    unsigned bytes;
  102.    char ack; /* If on (set to 1) the receiver must
  103.                       ACK data block if good.
  104.  
  105.              */
  106.   };
  107.  
  108. struct _info_header
  109.  {
  110.   unsigned flags;
  111.   /* 00000000 00000001 = Can handle Continues Stream Transmissions.
  112.  
  113.                          If this flag is off, ACK is required following
  114.                          each block of data.
  115.  
  116.                          ACKING each block of data turns Zmax into a
  117.                          X/Ymodem Batch type protocol.
  118.  
  119.                          It is suggested that once you reach 128
  120.                          byte blocks, bad lines, Zmax should
  121.                          require each block of data to be ACKED.
  122.  
  123.                          This  will switch it to a batch
  124.                          Xmodem style protocol which is
  125.                          better for bad phone lines.
  126.  
  127.                          You'll also notice that although there are
  128.                          provisions for decreasing the block size
  129.                          when noisy lines are encountered, you don't
  130.                          see any place where I raise the block size back
  131.                          up.
  132.  
  133.                          There is nothing saying you CAN'T do that, I just
  134.                          don't beleive you should. If you encounter
  135.                          enough noise to cause the block size to drop, then
  136.                          the likely hood of you encountering MORE is very high.
  137.  
  138.                          If you do raise the block size back up, I would recommend
  139.                          that you do it based on TIME and not number of good block
  140.                          sent. Given that 13 blocks (256 byte blocks) can be
  141.                          stuffed into a 3K TX buffer, you may THINK you've sent
  142.                          13 good blocks when in fact the very next one you sent
  143.                          could be bad. I think 10 to 20 seconds without an error
  144.                          would be a good time frame.
  145.  
  146.                          You'll also notice that I do not drop the block size
  147.                          on the first error. One error does not make for bad
  148.                          phone lines, 2 or more does.
  149.  
  150.                          If you decide to use large blocks than I do here,
  151.                          then you may want to go ahead and drop them on the
  152.                          first error.
  153.  
  154.  
  155.                          */
  156.  
  157.  
  158.   int   buf_size;      /* Used to pass transmitter the receivers max
  159.                         buffer size. Its is suggested that the receiver
  160.                         support 2K buffer.
  161.  
  162.                         The transmitter doesn't have to give you those
  163.                         sizes and can replace them with his own as long
  164.                         as it is less than or equal to your max buffer
  165.                         size.
  166.  
  167.                         Nor do the block sizes have to be powers of 2.
  168.  
  169.                         You can use odd block sizes...231, 888, etc.
  170.  
  171.                         I used powers of 2 because of the way DOS formats
  172.                         harddrives, ie. cluster size.
  173.  
  174.                         You'll also notice that Zmax places little restrictions
  175.                         on the maximum SIZE of the block although going over
  176.                         2048 shows little gain and lots of loses when a resend
  177.                         is requested.
  178.  
  179.                         To give you some guidelines for setting block sizes
  180.                         see chart below:
  181.  
  182.                         Chart based on sending a 60,416 byte file WITH the
  183.                         protocol overhead figured in and driving the serial
  184.                         port to its maximum Cps at that baud rate which this
  185.                         driver does.
  186.  
  187.                         Blk Size                     Tx Time
  188.                          Bytes                    2400    9600 LOCKED Port.
  189.  
  190.                           64                      318.60  79.65
  191.                          128                      285.17  71.29
  192.                          256                      268.45  67.11
  193.                          512                      260.09  65.02
  194.                         1024                      255.91  63.98
  195.                         2048                      253.82  63.46
  196.                         4096                      252.78  63.20
  197.                         8192                      252.26  63.07
  198.  
  199.                         As you can see, there's quite a bit of savings
  200.                         across the baud rate scale with each increament
  201.                         of the block size up to 2048 bytes. Once you exceed
  202.                         2048 BPB, the savings is almost not measureable.
  203.  
  204.                         Taking into account the time required to resend 2K of
  205.                         data at 2400 bps, I wouldn't risk going over 1K at 2400
  206.                         unless the call is local or under MNP.
  207.  
  208.                         You may REQUEST any size data block up to
  209.                         the size of a signed integer.
  210.  
  211.  
  212.                         */
  213.    unsigned char version ; /*
  214.  
  215.                      This allows for future expansion to the protocol
  216.                      and still yet allow for backwards compatibly.
  217.  
  218.                      This is the version of the protocol specs that the
  219.                      receiver supports. Currently this should be set to one.
  220.  
  221.                    */
  222.   char empty[123]; /* Reserves an extra 123 bytes for future expansion */
  223.  };
  224.  
  225. /* DEFINES */
  226.  
  227. #define STX 2
  228. #define TSYNCH 0xae
  229. #define ACK 0x06
  230. #define NAK 0x15
  231. #define SOH 0x01
  232. #define EOT 0x04
  233. #define CAN 0x18
  234. #define RESYNC 9
  235. #define PER_WEEK  60480000L
  236. #define PER_DAY    8640000L
  237. #define PER_HOUR    360000L
  238. #define PER_MINUTE    6000L
  239. #define PER_SECOND     100L
  240. #define ENQ 0x05
  241.  
  242. main(int argc, char *argv[])
  243. {
  244. /*
  245.  
  246.    This is the main section of this driver. It's makeup is entirely
  247.    up to you. With of course, several REQUIRED sets.
  248.  
  249.    */
  250. int i,x,count,can_display_user_name=0;
  251. int y=0,block_size=1024;
  252. int send=0,do_acks=0;
  253. char s[81],s1[81];
  254. FILE *in;
  255. qvideo();
  256. clrscrn();
  257. Screen_ptr = malloc(1 * 4000);
  258. if(Screen_ptr == NULL) exit(1);
  259. uncomprs(&Screen_ptr[0*4000], tmod); /* uncompress screen 1 */
  260. memtoscr(2000, 0, Screen_ptr);
  261. curoff();
  262. memset(s,'\0',sizeof(s));
  263. if(!envget2("OSIRIS",s))
  264.    {
  265.    sprintf(log_file,"%s\\Zmax.log",s);
  266.    can_display_user_name=1;
  267.    }
  268. else
  269.    sprintf(log_file,"Zmax.log");
  270. for(i=1;i<argc;i++)
  271.  {
  272.   if(argv[i][0] == '/' || argv[i][0] == '-')
  273.   {
  274.     switch(toupper(argv[i][1]))
  275.     {
  276.     case 'N' :
  277.                if(can_display_user_name)
  278.                {
  279.                 sprintf(s1,"%s\\node%d",s,atoi(argv[i+1]));
  280.                 in = fopen(s1,"r");
  281.                 fgets(s,80,in);
  282.                 fclose(in);
  283.                 s[strlen(s)] = '\0';
  284.                 curlocat(23,2);
  285.                 colrprts(s,15,1);
  286.                }
  287.                break;
  288.     case 'S' : block_size = atoi(argv[i+1]);
  289.                if(block_size > 2048)
  290.                              block_size = 2048;
  291.                break;
  292.     case 'A' : do_acks = 1;break;
  293.     case 'K' : delete_aborted_transfers = 0;
  294.                break;
  295.     case 'P' : port_ptr = atoi(argv[i+1]);
  296.                port_ptr--;
  297.                break;
  298.     case 'B' : connect_rate = atoi(argv[i+1]);
  299.                cur_baud = connect_rate;
  300.                block_size = (connect_rate > 2400) ? 2048 : 1024;
  301.                break;
  302.     case 'L' : locked_port = atol(argv[i+1]);
  303.                break;
  304.     case 'R' : set_com();
  305.  
  306.                /*
  307.                  You should continue to cycle receiving files until
  308.                  Zrecfile returns a ZERO, indicating that it did not
  309.                  receive any files or the session was aborted.
  310.                  */
  311.                while ( Zrecfile(do_acks,block_size) && (async_carrier(port))) clear_screen() ;
  312.  
  313.                /* Following the last file, the sender will require an ACK
  314.                   to signal the receivers acknowledges end of session.
  315.  
  316.                   The Sender doesn't respond back after receiving the ACK so
  317.                   continue with you processing after sending a couple of
  318.                   ACKS. Two is suggested, an extra incase line noise blew the
  319.                   first one.
  320.  
  321.                   */
  322.  
  323.                com_putc(ACK);
  324.                com_putc(ACK);
  325.                end_prg();
  326.                break;
  327.  
  328.     case 'F' : set_com();
  329.                i++;
  330.                for(;i<argc;i++)
  331.                 {
  332.                  memset(s,'\0',sizeof(s));
  333.                  parser(argv[i],&s[0]);
  334.  
  335.                  /* Cycle until all files are sent or Zsendfile returns
  336.                     a zero indicating Session was aborted. */
  337.                  acks_required = 0;
  338.                  if(!Zsendfile(argv[i],s))
  339.                        end_prg();
  340.                  if(!async_carrier(port)) end_prg();
  341.                  clear_screen();
  342.                 }
  343.                 i = count = 0;
  344.  
  345.                 /*
  346.                     Signal end of Batch Transfer.
  347.  
  348.                     Cycle sending EOT until receiver sees it and ACKs
  349.                     the ending EOT. I suggest cycling only two periods
  350.                     , period being defined as trying ACKEOT function twice.
  351.  
  352.                     If your using Zmax in a mailer environment and as the
  353.                     sender you find that you have NOTHING to send, then bypass
  354.                     the Zsendfile routine and go directly to this section.
  355.  
  356.                 */
  357.  
  358.                 while(!count && i <= 1)
  359.                   {
  360.                    com_putc(EOT);
  361.                    i++;
  362.                    if(ackeot()) count = 1;
  363.                    if(!async_carrier(port)) count = 1;
  364.                   }
  365.                 end_prg();
  366.                 break;
  367.    }
  368.  }
  369.  }
  370.  
  371. }
  372. Zsendfile(name,s_name)                      /* transmit a file */
  373. char *name;           /* FULL Drive, path, and name of file to send */
  374. char s_name[]; /*   Only the filename, fit to be used in  file info
  375.                       header.
  376.                  */
  377.  
  378.  
  379. {
  380.     long location, blkloc,size,st,ft,t1,t2;
  381.     int error=0,endblk,x,y,i,cps;
  382.     struct Zhead zero;
  383.     struct _info_header info_header;
  384.     unsigned file_date,file_time,actual;
  385.     char s[80];
  386.     int ok;
  387.     struct _block_header block_header;
  388.     if(!async_carrier(port)) return(0);
  389.     acks_required = 1;
  390.     async_txflush(port);
  391.     file_position = 0L;
  392.  
  393.          if(!filexist(name)) return(1);
  394.  
  395.          x = openfil(name,2,&sending_file);
  396.          getstamp(sending_file,&file_date,&file_time);
  397.          memset(&zero,'\0',sizeof(zero)); /* clear out data block */
  398.          filsize(name,&size);
  399.          percent_size = size / 40;
  400.          seof = size;
  401.          strcpy(zero.fnam,s_name);
  402.          zero.fdate = (unsigned) file_date;
  403.          zero.ftime = (unsigned) file_time;
  404.          zero.flen =  (long) size;
  405.          curlocat(5,28);
  406.          colrprtf(0,0,7,"%-14s",zero.fnam);
  407.          curlocat(6,28);
  408.          colrprtf(0,0,7,"%-7ld",size);
  409.          amt_sent = 0L;
  410.  
  411.          total_errors =  cancel =   0;
  412.          t1 = timerset(6000L);                /* time limit for first block */
  413.          com_putc(TSYNCH);
  414.          com_putc(TSYNCH);
  415.          endsend = i = 0;
  416.          while(x != 'C' && !timeup(t1)) /* Wait for primer start */
  417.           {
  418.            x = com_getc(2);
  419.            if(x != 'C')
  420.                com_putc(TSYNCH);
  421.            if(!async_carrier(port)) return(0);
  422.            if(x == 0x18) cancel++;
  423.            if(cancel > 3)
  424.             {
  425.              curlocat(7,28);
  426.              colrprtf(0,0,7,"%-40s","Rcv Canceled Transfer");
  427.              closefil(sending_file);
  428.              end_prg();
  429.             }
  430.           }
  431.           cancel = 0;
  432.           if(x != 'C')
  433.                 goto abort; /* If we did not get it then abort */
  434.  
  435.           ok = 0;
  436.           while(!get_system_info(&info_header) && async_carrier(port))
  437.             {
  438.             if(++ok > 3)
  439.                async_dtr(port,0); /* After 3 attempts, drop carrier
  440.                                      and bail out.
  441.                                   */
  442.             }
  443.           if(!async_carrier(port)) goto abort;
  444.  
  445.           block_len = info_header.buf_size;
  446.           if(block_len > 2048)
  447.                        block_len = 2048;
  448.           if( (info_header.flags&0x0001))
  449.                            acks_required = 0;
  450.           cancel = ok = 0;
  451.  
  452.           curlocat(7,28);
  453.           colrprtf(0,0,7,"%-40s","Sending File Header");
  454.        while(!ok)
  455.        {
  456.           async_rxflush(port);
  457.           SendHeader(&zero);
  458.           switch(wait_ack())
  459.                {
  460.                        case 1:  break; /* I treat both an Abort and
  461.                                           a duplicate the same to save
  462.                                           a little space. You don't have
  463.                                           to.
  464.  
  465.                        case 2:
  466.                                closefil(sending_file);
  467.                                curlocat(7,28);
  468.                                colrprtf(0,0,7,"%-40s","Rcv Already has File");
  469.                                return(1);
  470.  
  471.                        case 3:/* REPOS ie. Restart */
  472.                        default: curlocat(7,28);
  473.                                 sprintf(junk_string,"BufSize %d (%sStream Mode)",info_header.buf_size,(acks_required) ? "Non-" : "");
  474.                                 colrprtf(0,0,7,"%-40s",junk_string);
  475.                                 ok = 1;
  476.                                 break;
  477.  
  478.                 }/* End switch  */
  479.      }
  480.  
  481.     st = timerset(0L);
  482.     async_rxflush(port);
  483.     async_txflush(port);
  484.     do
  485.     {
  486.               if( !async_carrier(port) )
  487.                   goto abort;
  488.               if(timeup(t1))
  489.                   goto abort;
  490.               if(checkkey())
  491.                       {
  492.                       i = getkey(&x);
  493.                        if(x == 27)
  494.                          {
  495.                              while(!async_txempty(port)){
  496.                                     if(!async_carrier(port)) break;
  497.                                     }
  498.                              cancel_transfer();
  499.                              goto abort;
  500.                          }
  501.                        }
  502.               ChkForNak();
  503.               while(file_position < zero.flen)/* loop until all sent */
  504.               {
  505.                        if(!async_carrier(port))
  506.                                         goto abort;
  507.                        ChkForNak();
  508.                        if(checkkey())
  509.                        {
  510.                          i = getkey(&x);
  511.                          if(x == 27)
  512.                          {
  513.                              while(!async_txempty(port)){
  514.                                     if(!async_carrier(port)) break;
  515.                                     }
  516.                              cancel_transfer();
  517.                              goto abort;
  518.                         }
  519.                        }
  520.                        /*
  521.                          NOTE: My file functions; seekfil,
  522.                          readfil, creatfil, openfil, writefil,
  523.                          etc. all have built in error handling
  524.                          routines to reduce redundent coding on
  525.                          MY part. You should add your own error
  526.                          trapping according to what your using.
  527.  
  528.                          */
  529.                        i = seekfil(sending_file,0,file_position,&location);
  530.                        i = readfil(sending_file,block_len,tbuf,&actual);
  531.  
  532.  
  533.                        /*
  534.                           Sending the current file position with
  535.                           each data block removes all
  536.                           possiblities of Desqview shifting the
  537.                           file position, a network or satellite
  538.                           link mis-routing or losing a block of
  539.                           data. I've seen both happen before and
  540.                           they weren't detected until the end of
  541.                           file.
  542.  
  543.                           This totally insures that the receiver
  544.                           and sender are never out of sync.*/
  545.  
  546.                        block_header.position = file_position;
  547.                        block_header.bytes = actual;
  548.                        block_header.ack = (acks_required) ? 1 : 0 ;
  549.                        file_position = (long) file_position + (long) actual;
  550.                        amt_sent = (long) file_position;
  551.                        com_putc(SOH);
  552.                        com_putc(ENQ);
  553.                        send_block_header(&block_header);
  554.                        SendDataBlock(tbuf,actual);
  555.                        if(block_header.ack)
  556.                         {
  557.                           while(!async_txempty(port))
  558.                                if(!async_carrier(port)) break; /* Wait till
  559.                                                                  its all out
  560.                                                                  before beginning
  561.                                                                  timer*/
  562.                           t2 = timerset(3000L);/* Give receiver 30
  563.                                                    seconds to ACK or
  564.                                                    NAK the block.
  565.                                                    30 seconds seems
  566.                                                    like a lot of time,
  567.                                                    but you have to allow
  568.                                                    for satellite/network delays,
  569.                                                    HST and Telebit ARQ resends.
  570.                                                    etc.
  571.                                                */
  572.                           ok = i = 0;
  573.                           while(!timeup(t2) && !ok)
  574.                            {
  575.                              i = com_getc(0);
  576.                              if(i == ACK) ok = 1;
  577.                              else
  578.                                if(i == 'C')
  579.                                {
  580.                                 i = com_getc(2);
  581.                                   if(i == '*')
  582.                                   {
  583.                                       if(GetNewPosition())
  584.                                                      ok = 1;
  585.  
  586.                                    }/* End Get REPOS */
  587.  
  588.                                 }/* End possible NAK */
  589.  
  590.                            } /* End 10 second timer loop */
  591.                            if(!ok)
  592.                             async_dtr(port,0); /* No responds in
  593.                                                   30 seconds, drop carrier
  594.                                                   and get out. */
  595.                         }/* End wait for ACK */
  596.                        else
  597.                           ChkForNak();
  598.                        if(file_position == zero.flen)
  599.                        {
  600.                            com_putc(EOT);
  601.                            endsend = 0;
  602.                            t1 = timerset(9000L);  /* time limit for last block if ackless(90 secs) */
  603.                            sprintf(junk_string,"%-7ld",zero.flen);
  604.                            curlocat(6,58);
  605.                            colrprtf(0,0,7,"%s",junk_string);
  606.                            for(i=1;i<=40;i++)
  607.                            {
  608.                               curlocat(19,(21+i));
  609.                               colrprtf(0,15,7,"█");
  610.                            }
  611.                         }
  612.                         ChkForNak();
  613.                         if(cancel >= 5) goto abort;
  614.               }/* Still to go */
  615.  
  616.               ChkForNak();
  617.               if(cancel >= 5) goto abort;
  618.     }while(!endsend);
  619.     /* end main send */
  620.  
  621.     ft = timerset(0L);
  622.     closefil(sending_file);
  623.       ft = (long) (ft-st) / 100L;
  624.       if(ft == 0) ft = 1L;
  625.       cps = (int) (zero.flen / ft);
  626.       x = (cps*10) / (connect_rate/100);
  627.       curlocat(14,28);
  628.       colrprtf(0,0,7,"%3d%%",x);
  629.       out = fopen(log_file,"a");
  630.       fprintf(out,"%d bps   %-14s   %-7ld   %3d%%\n",connect_rate,zero.fnam,zero.flen,x);
  631.       fclose(out);
  632.       return_code = 0;
  633.       return(1);                          /* exit with good status */
  634.  
  635. abort:
  636.     async_txflush(port);
  637.     closefil(sending_file);
  638.     return(0);                          /* exit with bad status */
  639. }
  640.  
  641.  
  642. ChkForNak()                        /* check for bad block */
  643. {
  644.     unsigned char c=0;
  645.     int q;
  646.     top:;
  647.        c = com_getc(0);
  648.       if(c == 'C' || c == ACK)
  649.        {
  650.              if(c == ACK)
  651.              {
  652.              if(file_position == seof)
  653.                               endsend = 1;
  654.              return;
  655.              }
  656.         q = com_getc(1);
  657.         if(q != '*')
  658.                   return;
  659.         async_txflush(port);
  660.         q = GetNewPosition();
  661.       }
  662.       else
  663.        if(c == CAN)
  664.              cancel++;
  665.  
  666. if( (async_rxcnt(port)))
  667.        goto top;
  668. }
  669.  
  670. SendDataBlock(blk,size)         /* physically ship a block */
  671. char *blk;                             /* data to be shipped */
  672. int size;/* size of block */
  673. {
  674. register i,x,y;
  675. unsigned long oldcrc;
  676. long location;
  677. static unsigned char ch;
  678. char *b = blk;
  679. char *j = blk;
  680. static int n,q,flow,aa,kk;
  681.  
  682.  
  683.           while(  (async_txblk(port, b, size)) == R_TXERR)
  684.           {
  685.                 curlocat(6,58);
  686.                 location = (long) file_position - size;
  687.                 colrprtf(0,0,7,"%-7ld",location);
  688.                 kk = location / percent_size;
  689.                 if(kk > 40) kk = 40;
  690.                 for(aa=1;aa<=kk;aa++)
  691.                            {
  692.                               curlocat(19,(21+aa));
  693.                               colrprtf(0,15,7,"█");
  694.                            }
  695.                 if(async_rxcnt(port))
  696.                 {
  697.                   flow = (async_peek(port,0)&0xff);
  698.                   if(flow == 'C')
  699.                    {
  700.                       async_txflush(port);
  701.                       return;
  702.                    }
  703.                    else
  704.                      if(flow != CAN)
  705.                           flow = async_rx(port); /* Eat non C/CAN char, more
  706.                                                     than likely was line noise
  707.                                                      */
  708.                 }
  709.                 else
  710.                   if(!async_carrier(port)) return;
  711.  
  712.          }/* end while*/
  713.           oldcrc = 0xFFFFFFFF;
  714.           for(n=0;n<size;n++){
  715.                   oldcrc = UpdCrc32(((unsigned short) (*j++)), oldcrc);
  716.                   }
  717.           oldcrc = ~oldcrc;
  718.         for(n=4; --n >=0;)
  719.         {
  720.           com_putc((unsigned char) oldcrc);
  721.            oldcrc >>= 8;
  722.         }
  723.         if(acks_required)
  724.         {
  725.                 curlocat(6,58);
  726.                 location = (long) file_position - size;
  727.                 colrprtf(0,0,7,"%-7ld",location);
  728.                 kk = location / percent_size;
  729.                 if(kk > 40) kk = 40;
  730.                 for(aa=1;aa<=kk;aa++)
  731.                            {
  732.                               curlocat(19,(21+aa));
  733.                               colrprtf(0,15,7,"█");
  734.                            }
  735.         }
  736. }
  737.  
  738. ackeot()
  739. {
  740. long t;
  741. int c;
  742. t = timerset(300L);
  743. while(!timeup(t))
  744. {
  745. c = com_getc(0);
  746.     if(c == ACK)
  747.             return(1);
  748. }
  749.  
  750. return(0);
  751. }
  752. long timerset (t)
  753. long t;
  754. {
  755.         long l;
  756.         int l2;
  757.         int hours,mins,secs,ths,year,month,day;
  758.  
  759.         sysitime (&hours,&mins,&secs,&ths);
  760.         sysidate(&year,&month,&day);
  761.         l2 = dayofwee(year,month,day);
  762.  
  763.         l =     l2      * PER_DAY       +
  764.                 hours   * PER_HOUR      +
  765.                 mins    * PER_MINUTE    +
  766.                 secs    * PER_SECOND    +
  767.                 ths                     ;
  768.  
  769.         l += t;
  770.  
  771.         return (l);
  772.         }
  773.  
  774. timeup (t)
  775. long t;
  776. {
  777.         long l;
  778.  
  779.         l = timerset (0L);
  780.         if(l < (t-PER_DAY)) l = l + PER_DAY;
  781.         return ((l - t) >= 0L);
  782.         }
  783.  
  784. com_getc(t)
  785. int t;
  786. {
  787.         static long t1,t2;
  788.         int c;
  789.         if(!((c = async_rx(port)) & B_RXEMPTY))
  790.                return((c&0xff));
  791.         t2 = (long) t * 100L;
  792.         t1 = timerset (t2);
  793.         while(((c = async_rx(port)) & B_RXEMPTY))
  794.                 {
  795.                 if(!async_carrier(port))
  796.                     {
  797.                     return(EOF);
  798.                     }
  799.                 if (timeup(t1))
  800.                         {
  801.                         return(EOF);
  802.                         }
  803.                 }
  804.         return((c&0xff));
  805.  
  806.  
  807.         }
  808. wait_ack()
  809. {
  810. int ch;
  811. long t;
  812. struct _block_header block_header;
  813.  
  814. t = timerset(3000L); /* If no rsponds in 30 seconds, skip file */
  815. for(;;)
  816.  {
  817.     ch = com_getc(5);
  818.     if(ch == 'D')
  819.       {
  820.             ch = com_getc(5);
  821.             if(ch == 'P')
  822.             {
  823.                com_putc(ACK);
  824.                return(2);
  825.             }
  826.       }/* End if Duplicate File */
  827.  
  828.     if(ch == ACK) return(4);
  829.  
  830.    if(ch == CAN || timeup(t))
  831.     {
  832.        async_rxflush(port);
  833.        return(2);
  834.     }
  835.  
  836.     if(ch == RESYNC)
  837.     {
  838.       if(get_block_header(&block_header))
  839.         {
  840.           file_position = block_header.position;
  841.           return(3);
  842.         }
  843.  
  844.     }/* Resync */
  845.  
  846.    if(ch == 'C')
  847.          return(1);
  848.  }
  849.  
  850. }
  851.  
  852. SendHeader(blk)                      /* physically ship Fileinfo block */
  853. char *blk;                             /* data to be shipped */
  854. {
  855. register ch,n;
  856. unsigned long oldcrc;                  /* CRC check value */
  857.  
  858.     com_putc(SOH);
  859.     com_putc(NAK);
  860.  
  861.     while(  (async_txblk(port, blk, 22)) == R_TXERR);
  862.  
  863.          oldcrc = 0xFFFFFFFF;
  864.           for(n=0;n<22;n++){
  865.                   oldcrc = UpdCrc32(((unsigned short) (*blk++)), oldcrc);
  866.                   }
  867.           oldcrc = ~oldcrc;
  868.         for(n=4; --n >=0;)
  869.         {
  870.           com_putc((unsigned char) oldcrc);
  871.            oldcrc >>= 8;
  872.         }
  873.  
  874. }
  875.  
  876. set_com()
  877. {
  878. char parms[80],s2[30],s3[30];
  879. int ch;
  880. long atol();
  881. if(port_ptr)
  882.    {
  883.    IOadrs = 0x2f8;
  884.    irqm = 0x08;
  885.    vctrn = 11;
  886.    }
  887. port = malloc(sizeof(ASYNC));
  888. sprintf(s3,"COM%d",port_ptr+1);
  889. memset(s2,'\0',sizeof(s2));
  890. if(!envget2(s3,s2))
  891.     locked_port = (long) atol(s2);
  892. if(locked_port)
  893. sprintf(parms,"%ldN81",locked_port);
  894. else
  895. sprintf(parms,"%dN81",cur_baud);
  896. if(!(AllocRingBuffer(port, 2048, 3072, 1)))/* Note that I allocate
  897.                                               a TX buffer 1K larger
  898.                                               than the largest block
  899.                                               size that I support.
  900.  
  901.                                               This gives me a little
  902.                                               breathing space in STREAM
  903.                                               mode at 9600+ for file management. */
  904.    exit(0);
  905. if ((ch = async_open(port, IOadrs, irqm, vctrn, parms)) != R_OK)
  906.           exit(0);
  907. async_rxflush(port);
  908. async_txflush(port);
  909. async_msrflow(port, B_CTS);
  910. async_FIFOtxlvl(port,4);/*
  911.                            I strongly suggest that you keep the
  912.                            FIFO Tx bytes per interrupt to no more
  913.                            than 4.
  914.  
  915.                            Reason:
  916.  
  917.                            This driver will drive the modem so
  918.                            fast and hard that an HST 450
  919.                            Backchannel will loose its sync with
  920.                            an HST Dual Standard or HST 14.4 if
  921.                            its (450) doing the sending.
  922.  
  923.  
  924.                         */
  925. async_FIFOrxlvl(port,1);/* Never go over 1 here */
  926. }
  927.  
  928. parser(s,name) char s[],name[];
  929. {
  930. char stack[80];
  931. int i,x;
  932. if(strindex("\\",s) == -1)
  933.  {
  934.   name[0] = 0;
  935.   strcpy(name,s);
  936.   return;
  937.  
  938.  }
  939.  
  940. memset(stack,'\0',sizeof(stack));
  941. x = strlen(s);
  942. i = 0;
  943. while(s[x] != '\\' && x > 0)
  944.   {
  945.   if(s[x] != 0 && s[x] != 13 && s[x] != 10) stack[i++] = s[x];
  946.   x--;
  947.   }
  948. x = 0;
  949. i--;
  950. while(i >= 0)
  951.    name[x++] = stack[i--];
  952. name[x] = '\0';
  953. }
  954.  
  955. end_prg()
  956. {
  957. curon();
  958. if(async_carrier(port))
  959.      port->OldMCR |= B_DTR;
  960. async_close(port);
  961. if(!delete_aborted_transfers)
  962.   sleep(20);
  963. exit(return_code);
  964.  
  965. }
  966.  
  967. Zrecfile(int do_acks,int block_size)                    /* receive file */
  968. {
  969.     int n,w,x,y,tries,i,c,cps;
  970.     char outname[81];
  971.     int kk,aa;
  972.     unsigned send,actual,file_date,file_time;
  973.     struct Zhead zero;                 /* file header data storage */
  974.     struct _block_header block_header;
  975.     struct _info_header SystemInfo;
  976.     long t1,st,ft,lsize,testl;
  977.  
  978.     cancel=tries = total_errors = c = 0;
  979.     percent_size = 32000;
  980.     memset(outname,'\0',sizeof(outname));
  981.     memset(&zero,'\0',sizeof(zero));
  982.     amt_sent = 0L;
  983.     file_position = 0L;
  984.     st = timerset(6000L);
  985.     com_putc(' ');
  986.     while(!timeup(st))
  987.     {
  988.          if(!async_carrier(port))
  989.                           return(0);
  990.      c = com_getc(1);
  991.      if(c == TSYNCH)
  992.          st =timerset(0L);
  993.      if(c == EOT)
  994.          return(0);
  995.  
  996.      if(c == ENQ)
  997.         {
  998.            com_putc(ACK);
  999.            st = timerset(30000L); /*
  1000.                                      This is relevant only if
  1001.                                      zmax is being used in a mailer
  1002.                                      application.
  1003.  
  1004.                                      ENQ at this point means to
  1005.                                      extend the time out period to 5 minutes.
  1006.  
  1007.                                      This is used primaryly for allowing
  1008.                                      service requests time to be processed
  1009.                                      by exteranl programs. See Mailer.Doc
  1010.                                      for information on service requests.
  1011.  
  1012.  
  1013.  
  1014.                                   */
  1015.         }
  1016.     }
  1017.     if(c != TSYNCH)
  1018.      {
  1019.          curlocat(7,28);
  1020.          colrprtf(0,0,7,"%-40s","Sender flobbed it");
  1021.          st = timerset(500L);
  1022.          while(!timeup(st)) ;
  1023.          return(0);
  1024.      }
  1025.  
  1026.     cancel = c = 0;
  1027.     st = 0L;
  1028.     com_putc('C');
  1029.     c = '\0';
  1030.     memset(&SystemInfo,'\0',sizeof(SystemInfo));
  1031.     if(!do_acks)
  1032.          SystemInfo.flags ^= 0x0001;
  1033.     SystemInfo.buf_size =  block_size;
  1034.     SystemInfo.version = 1;
  1035.  
  1036.     send_system_info(&SystemInfo);
  1037.  
  1038.     curlocat(7,28);
  1039.     colrprtf(0,0,7,"%-40s","Waiting For File");
  1040.  
  1041.     goto nextblock;
  1042.  
  1043. badblock:                              /* we got a bad block */
  1044.  
  1045.     if(++tries>10)
  1046.     {
  1047.          async_dtr(port,0);
  1048.          sleep(3);
  1049.          async_dtr(port,1);
  1050.          goto abort;
  1051.     }
  1052.     async_rxflush(port);
  1053.     send_resync();
  1054.     i = seekfil(send,2,0L,&testl);
  1055.     curlocat(5,58);
  1056.     colrprtf(0,0,7,"%d",++total_errors);
  1057.     goto nextblock;
  1058.  
  1059. goodblock:                              /* we got a good block */
  1060.     if(block_header.ack)
  1061.                  com_putc(ACK);
  1062.     amt_sent = (long) file_position;
  1063.  
  1064. nextblock:                             /* start of "get a block" */
  1065.     t1 = timerset(2000L);
  1066.     while(!timeup(t1))
  1067.     {
  1068.          if(checkkey())
  1069.          {
  1070.           aa = getkey(&kk);
  1071.           if(kk == 27)
  1072.            {
  1073.             cancel_transfer();
  1074.             goto abort;
  1075.            }
  1076.          }
  1077.          c = (com_getc(3)&0xff);
  1078.          switch (c)
  1079.          {
  1080.          case CAN : cancel++;
  1081.                     if(cancel >= 5)
  1082.                            goto abort;
  1083.                     break;
  1084.          case SOH :
  1085.                         x = com_getc(5);
  1086.                         switch(x)
  1087.                            {
  1088.                               case NAK :
  1089.                                             if(readblock(&zero,22))
  1090.                                               {
  1091.                                                      st = timerset(0L);
  1092.                                                      sprintf(outname,"%s",zero.fnam);
  1093.                                                      if(!filexist(outname))
  1094.                                                                  com_putc(ACK);
  1095.                                                         if(filexist(outname))
  1096.                                                           {
  1097.                                                              openfil(outname,2,&send);
  1098.                                                              getstamp(send,&file_date,&file_time);
  1099.                                                              closefil(send);
  1100.                                                              filsize(outname,&lsize);
  1101.                                                              if(lsize < zero.flen && zero.fdate == file_date && zero.ftime == file_time)
  1102.                                                                 {
  1103.                                                                      openfil(outname,2,&send);
  1104.                                                                      seekfil(send,2,0L,&file_position);
  1105.                                                                      curlocat(7,28);
  1106.                                                                      sprintf(junk_string,"Re-Start: %ld",file_position);
  1107.                                                                      colrprtf(0,0,7,"%-40s",junk_string);
  1108.                                                                      com_putc(RESYNC);
  1109.                                                                      block_header.position = file_position;
  1110.                                                                      send_block_header(&block_header);
  1111.                                                                  }
  1112.                                                                  else
  1113.                                                                  {
  1114.                                                                       if(lsize == zero.flen && zero.fdate == file_date && zero.ftime == file_time)
  1115.                                                                        {
  1116.                                                                           x = i = 0;
  1117.                                                                           curlocat(7,28);
  1118.                                                                           colrprtf(0,0,7,"%-40s","Duplicate: Asking for Skip");
  1119.                                                                           async_rxflush(port);
  1120.                                                                           com_putc('D');
  1121.                                                                           com_putc('P');
  1122.                                                                           c = com_getc(5);
  1123.                                                                           if(c == ACK)
  1124.                                                                                return(1);
  1125.  
  1126.                                                                           return(0);
  1127.                                                                        }
  1128.  
  1129.                                                                  }
  1130.                                                          } /* end if exits */
  1131.                                                          else
  1132.                                                              i = creatfil(outname,0,&send);
  1133.                                                          curlocat(5,28);
  1134.                                                          colrprtf(0,0,7,"%-14s",outname);
  1135.                                                          curlocat(6,28);
  1136.                                                          colrprtf(0,0,7,"%-7ld",zero.flen);
  1137.                                                          percent_size  = zero.flen / 40;
  1138.                                                          curlocat(7,28);
  1139.                                                          colrprtf(0,0,7,"%-40s","Getting File");
  1140.  
  1141.                                                          goto goodblock;
  1142.                                                }
  1143.                                                 curlocat(7,28);
  1144.                                                 colrprtf(0,0,7,"%-40s","Bad File Header");
  1145.                                                 com_putc('C');
  1146.                                                 goto nextblock;           /* bad header block */
  1147.                                         break;
  1148.                               case ENQ :memset(&block_header,'\0',sizeof(block_header));
  1149.                                         if(get_block_header(&block_header))
  1150.                                         {
  1151.                                           if(block_header.position != file_position)
  1152.                                            {
  1153.                                                  curlocat(7,28);
  1154.                                                  sprintf(junk_string,"Got %ld, Needed %ld",block_header.position,file_position);
  1155.                                                  colrprtf(0,0,7,"%-40s",junk_string);
  1156.                                                  goto badblock;
  1157.                                            }
  1158.                                            if(readblock(&tbuf[0],block_header.bytes))      /* else if we get it okay */
  1159.                                               {
  1160.                                                  n = writefil(send,block_header.bytes,tbuf,&actual);
  1161.                                                  file_position = (long) file_position + (long) actual;
  1162.                                                  curlocat(6,58);
  1163.                                                  colrprtf(0,0,7,"%-7ld",file_position);
  1164.                                                  cancel = tries = 0;
  1165.                                                  kk = file_position / percent_size;
  1166.                                                  if(kk > 40) kk = 40;
  1167.                                                  for(aa=1;aa<=kk;aa++)
  1168.                                                   {
  1169.                                                      curlocat(19,(21+aa));
  1170.                                                      colrprtf(0,15,7,"█");
  1171.                                                   }
  1172.                                                  goto goodblock;
  1173.                                                }
  1174.                                                  curlocat(7,28);
  1175.                                                  sprintf(junk_string,"Bad Block, REPOS %ld",file_position);
  1176.                                                  colrprtf(0,0,7,"%-40s",junk_string);
  1177.                                                 goto badblock;
  1178.                                         }
  1179.                                         goto badblock;
  1180.                                         break;
  1181.                              default :curlocat(7,28);
  1182.                                       sprintf(junk_string,"Huh?? (%02x)",x);
  1183.                                       colrprtf(0,0,7,"%-40s",junk_string);
  1184.                                       goto badblock;
  1185.  
  1186.                             }/* end switch x*/
  1187.                          break;
  1188.          case EOT :
  1189.                     if(file_position == zero.flen || file_position == 0)
  1190.                     {
  1191.                                 com_putc(ACK);
  1192.                                 if(file_position == 0) return(0);
  1193.                                 ft = timerset(0L);
  1194.                                 sprintf(junk_string,"%-7ld",zero.flen);
  1195.                                 curlocat(6,58);
  1196.                                 colrprtf(0,0,7,"%s",junk_string);
  1197.                                 closefil(send);
  1198.                                 openfil(outname,2,&send);
  1199.                                 setstamp(send,zero.fdate,zero.ftime);
  1200.                                 closefil(send);
  1201.                                  for(i=1;i<=40;i++)
  1202.                                   {
  1203.                                     curlocat(19,(21+i));
  1204.                                    colrprtf(0,15,7,"█");
  1205.                                   }
  1206.                                   ft = (long) (ft - st) /100L;
  1207.                                   if(ft == 0) ft = 1L;
  1208.                                   cps = (int) (zero.flen / ft);
  1209.                                   i = (connect_rate/100);
  1210.                                   if(i<=0)i=1;
  1211.                                   x = (cps*10) / i;
  1212.                                   curlocat(14,28);
  1213.                                   return_code = 0;
  1214.                                   colrprtf(0,0,7,"%3d%%",x);
  1215.                                   out = fopen(log_file,"a");
  1216.                                   fprintf(out,"%d bps   %-14s   %-7ld   %3d%%\n",connect_rate,zero.fnam,zero.flen,x);
  1217.                                   fclose(out);
  1218.                                   return(1);
  1219.  
  1220.                     }
  1221.                     break;
  1222.          }
  1223.     if(!async_carrier(port)){
  1224.          goto abort;
  1225.          }
  1226.    }
  1227.     curlocat(7,28);
  1228.     sprintf(junk_string,"Timeout, Position %ld",file_position);
  1229.     colrprtf(0,0,7,"%-40s",junk_string);
  1230.     goto badblock;
  1231. abort:
  1232.   async_rxflush(port);
  1233.   if(file_position > 0 )
  1234.    {
  1235.     closefil(send);
  1236.     openfil(outname,2,&send);
  1237.     setstamp(send,zero.fdate,zero.ftime);
  1238.     closefil(send);
  1239.     if(delete_aborted_transfers)
  1240.                     unlink(outname);
  1241.    }
  1242.    else
  1243.        return(0);
  1244. }
  1245.  
  1246.  
  1247. readblock(buf,size)             /* read a block of data */
  1248. char *buf;                             /* data buffer */
  1249. int size;
  1250. {
  1251.     register n;
  1252.     unsigned long crc;            /* CRC check values */
  1253.     long t1;  /* short block timeout */
  1254.     int x,c;
  1255.     char *p = buf;
  1256.     char *s = buf;
  1257.  
  1258.     n = 0;
  1259.     c = size;
  1260.  
  1261.     while(n<size)
  1262.     {
  1263.            x = async_rxblk(port,s,c);
  1264.            n+=x,c-=x,s+=x;
  1265.            if(!(async_rxcnt(port)) && n<size)
  1266.              {
  1267.                  t1 = timerset(1000L);
  1268.                  while(!timeup(t1) && !async_rxcnt(port))
  1269.                   {
  1270.                      if(!async_carrier(port)) return(0);
  1271.                  }
  1272.                 if(timeup(t1)) return(0);
  1273.              }/* end if */
  1274.  
  1275.     } /* end while n<size */
  1276.       crc = 0xFFFFFFFF;
  1277.       for(n=0;n<size;n++){
  1278.                   crc = UpdCrc32(((unsigned short) (*p++)), crc);
  1279.                   }
  1280.  
  1281.        for (n = 4; --n >= 0;)
  1282.        {
  1283.          c = com_getc(2);
  1284.          crc = UpdCrc32(c, crc);
  1285.        }
  1286.    if (crc != 0xDEBB20E3)
  1287.       {
  1288.       return(0);
  1289.       }
  1290.       return(1);
  1291. }
  1292.  
  1293.  
  1294. com_putc(int t)
  1295. {
  1296.  
  1297.     if(!async_carrier(port)) return;
  1298.  
  1299.     while((async_tx(port,t)) == R_TXERR)
  1300.     {
  1301.       if(!async_carrier(port)) return;
  1302.     }
  1303.  
  1304.  
  1305. }
  1306.  
  1307. sleep(delay)
  1308. int delay;
  1309. {
  1310. long a;
  1311. a = timerset( (long) (delay * 10L) );
  1312. while(!timeup(a)) ;
  1313. }
  1314.  
  1315. clear_screen()
  1316. {
  1317. int x;
  1318. curlocat(4,28); colrprtf(0,0,7,"%-19s","");
  1319. curlocat(5,28); colrprtf(0,0,7,"%-14s","");
  1320. curlocat(6,28); colrprtf(0,0,7,"%-8s","");
  1321. curlocat(7,28); colrprtf(0,0,7,"%-40s","");
  1322. curlocat(5,58); colrprtf(0,0,7,"%-3s","");
  1323. curlocat(6,58); colrprtf(0,0,7,"%-7s","");
  1324. for(x=1;x<=40;x++)
  1325.  {
  1326.   curlocat(19,(21+x));
  1327.     colrprtf(0,0,7,"▓");
  1328.  }
  1329. }
  1330.  
  1331. get_block_header(char *buf)
  1332. {
  1333.     register n;
  1334.     unsigned long crc;
  1335.     int c,x;
  1336.     long t1;
  1337.     char *s = buf;
  1338.     char *p = buf;
  1339.  
  1340.     n = 0;
  1341.     c = 7;
  1342.  
  1343.     while(n<7)
  1344.     {
  1345.            x = async_rxblk(port,s,c);
  1346.            n+=x,c-=x,s+=x;
  1347.            if(!(async_rxcnt(port)) && n<7)
  1348.              {
  1349.                  t1 = timerset(1000L);
  1350.                  while(!timeup(t1) && !async_rxcnt(port))
  1351.                   {
  1352.                      if(!async_carrier(port)) return(0);
  1353.                   }
  1354.                 if(timeup(t1)) return(0);
  1355.              }/* end if */
  1356.  
  1357.     } /* end while n<7 */
  1358.       crc = 0xFFFFFFFF;
  1359.       for(n=0;n<7;n++){
  1360.                   crc = UpdCrc32(((unsigned short) (*p++)), crc);
  1361.                   }
  1362.  
  1363.        for (n = 4; --n >= 0;)
  1364.        {
  1365.          c = com_getc(2);
  1366.          crc = UpdCrc32(c, crc);
  1367.        }
  1368.  
  1369.    if (crc != 0xDEBB20E3)
  1370.                     return(0);
  1371.  
  1372. return(1);
  1373.  
  1374. }
  1375.  
  1376. send_block_header(char *b)
  1377. {
  1378. register n;
  1379. unsigned long oldcrc;
  1380. /*
  1381.  
  1382. Considerable thought went into making the decision to split the
  1383. header block apart from the actual data block.
  1384.  
  1385. Including it as part of the block would mean that only one CRC
  1386. would have to be sent, but considering that this information is
  1387. critical to the proper reception of the block (size and file
  1388. position), it could then be used for error repositioning and
  1389. restarts without additional code (some computers will be running
  1390. under memory restrictions that IBM Compatibles may not have), and
  1391. finally... I couldn't tell any difference either way, speed wise.
  1392.  
  1393. I elected to go for the additional reliablity and reduced code
  1394. size and keep them apart.
  1395.  
  1396. */
  1397. while(  (async_txblk(port, b, 7)) == R_TXERR) ;
  1398.  
  1399.           oldcrc = 0xFFFFFFFF;
  1400.           for(n=0;n<7;n++){
  1401.                   oldcrc = UpdCrc32(((unsigned short) (*b++)), oldcrc);
  1402.                   }
  1403.           oldcrc = ~oldcrc;
  1404.           for(n=4; --n >=0;)
  1405.            {
  1406.               com_putc((unsigned char) oldcrc);
  1407.               oldcrc >>= 8;
  1408.            }
  1409. }
  1410.  
  1411. get_system_info(char *buf)
  1412. {
  1413.     register n;
  1414.     unsigned long crc;
  1415.     int c,x;
  1416.     long t1;
  1417.     char *s = buf;
  1418.     char *p = buf;
  1419. curlocat(7,28);
  1420. colrprtf(0,0,7,"%-40s","Waiting For System Information");
  1421.  
  1422.     n = 0;
  1423.     c = 128;
  1424.  
  1425.     while(n<128)
  1426.     {
  1427.            x = async_rxblk(port,s,c);
  1428.            n+=x,c-=x,s+=x;
  1429.            if(!(async_rxcnt(port)) && n<128)
  1430.              {
  1431.                  t1 = timerset(1000L);
  1432.                  while(!timeup(t1) && !async_rxcnt(port))
  1433.                   {
  1434.                      if(!async_carrier(port)) return(0);
  1435.                   }
  1436.                 if(timeup(t1)) return(0);
  1437.              }/* end if */
  1438.  
  1439.     } /* end while n<128 */
  1440.       crc = 0xFFFFFFFF;
  1441.       for(n=0;n<128;n++){
  1442.                   crc = UpdCrc32(((unsigned short) (*p++)), crc);
  1443.                   }
  1444.  
  1445.        for (n = 4; --n >= 0;)
  1446.        {
  1447.          c = com_getc(2);
  1448.          crc = UpdCrc32(c, crc);
  1449.        }
  1450.  
  1451.    if (crc != 0xDEBB20E3){
  1452.              com_putc('C');
  1453.              return(0);
  1454.              }
  1455.  
  1456. com_putc(ACK);
  1457. return(1);
  1458. }
  1459.  
  1460. send_system_info(char *b)
  1461. {
  1462. register n;
  1463. int c,attempts=0;
  1464. unsigned long oldcrc;
  1465. char *p;
  1466. curlocat(7,28);
  1467. colrprtf(0,0,7,"%-40s","Sending System Information");
  1468. async_rxflush(port);
  1469. while(async_rxcnt(port)){
  1470.           async_rxflush(port);
  1471.           }
  1472. for(;;)
  1473. {
  1474.  
  1475.          while(  (async_txblk(port, b, 128)) == R_TXERR) ;
  1476.  
  1477.           oldcrc = 0xFFFFFFFF;
  1478.           p = b;
  1479.           for(n=0;n<128;n++){
  1480.                   oldcrc = UpdCrc32(((unsigned short) (*p++)), oldcrc);
  1481.                   }
  1482.           oldcrc = ~oldcrc;
  1483.           for(n=4; --n >=0;)
  1484.            {
  1485.               com_putc((unsigned char) oldcrc);
  1486.               oldcrc >>= 8;
  1487.            }
  1488.            c = com_getc(5);
  1489.            if(c == ACK) return;
  1490.            if(++attempts > 3)
  1491.            {
  1492.                 async_dtr(port,0);
  1493.                 sleep(3);
  1494.                 async_dtr(port,1);
  1495.                 return;
  1496.            }/* Screw it, drop connection and try later */
  1497.  
  1498. }/* End send system info */
  1499.  
  1500. }
  1501. cancel_transfer()
  1502. {
  1503.  
  1504. /* only 5 CAN's needed to abort a session, but I like
  1505.    to send more thans actual needed. */
  1506.  
  1507. com_putc(CAN);
  1508. com_putc(CAN);
  1509. com_putc(CAN);
  1510. com_putc(CAN);
  1511. com_putc(CAN);
  1512. com_putc(CAN);
  1513. com_putc(CAN);
  1514. com_putc(CAN);
  1515. com_putc(CAN);
  1516. com_putc(CAN);
  1517. com_putc(CAN);
  1518. com_putc(CAN);
  1519. com_putc(CAN);
  1520. com_putc(CAN);
  1521. com_putc(CAN);
  1522. com_putc(CAN);
  1523. com_putc(CAN);
  1524. com_putc(CAN);
  1525. com_putc(CAN);
  1526. com_putc(CAN);
  1527. while(!async_txempty(port))
  1528.        if(!async_carrier(port)) break;
  1529. }
  1530. send_resync()
  1531. {
  1532. long t1,t2;
  1533. int ch;
  1534. struct _block_header block_header;
  1535.  /* Here is where the receiver does all of the
  1536.     actual resend requests.
  1537.  
  1538.     The receiver will send the resend request every 1.5
  1539.     seconds until the sender acknowledges that he has
  1540.     received it.
  1541.  
  1542.     At that point, the receiver will go into a wait loop
  1543.     eating everything that comes in until NO data is present
  1544.     before giving the sender the OK to resume sending.
  1545.  
  1546.     This means that when we go back to the receive file loop,
  1547.     the buffers will be clear and the next characters should
  1548.     be the start of the next block.
  1549.  
  1550.     This also gives us a chance to clear out any garbage caused
  1551.     by a burst of static on the phone line.
  1552.  
  1553.    */
  1554.    com_putc('C');com_putc('*');
  1555.    block_header.position = file_position;
  1556.    send_block_header(&block_header);
  1557.  
  1558.   t1 = timerset(150L);
  1559.   t2 = timerset(6000L);
  1560.  
  1561.   for(;;)
  1562.   {
  1563.     if(!async_carrier(port))
  1564.                          return;
  1565.     if(timeup(t2))
  1566.         {/* if you can't get the sender to acknowledge your request
  1567.             within a reasonable time frame, 60 seconds in this
  1568.             case, then something is really wrong. Best to drop
  1569.             carrier and try later.
  1570.  
  1571.             60 Seconds can be shorter if you like, but bare in mind
  1572.             that HSTs and TELEBITS are half duplex modems and can
  1573.             have some trouble turning around and accepting incoming
  1574.             data when there sending full bore.
  1575.  
  1576.            */
  1577.           async_dtr(port,0);
  1578.           return;
  1579.         }
  1580.     if(com_getc(2) == ACK) /* I *THINK* that this method is
  1581.                               slightly faster than using a compound
  1582.                               conditional statment, as least with
  1583.                               my compiler. */
  1584.     {
  1585.       if(com_getc(1) == '*')
  1586.       {
  1587.          if(com_getc(1) == ACK)
  1588.          {
  1589.            if(com_getc(1) == '*')
  1590.              {
  1591.                t1 = timerset(1000L);
  1592.                 while (readbyte(1) != 0)
  1593.                  {
  1594.                    ch = com_getc(0);
  1595.                    if(timeup(t1))
  1596.                             return;
  1597.                  }
  1598.               com_putc(SOH);
  1599.               return;
  1600.             }
  1601.          }
  1602.      }
  1603.     }
  1604.      if(timeup(t1)){
  1605.      com_putc('C');com_putc('*');
  1606.      block_header.position = file_position;
  1607.      send_block_header(&block_header);
  1608.      t1 = timerset(150L);
  1609.      }
  1610.   }
  1611. }
  1612. readbyte(t)
  1613. int t;
  1614. {
  1615. unsigned char c;
  1616. long t1,t2;
  1617. t2 = (long) t * 100;
  1618. if (async_rxcnt(port))
  1619.        return(1);
  1620. t1 = timerset (t2);
  1621. while (!(async_rxcnt(port)))
  1622.   {
  1623.    if (timeup (t1))
  1624.            return (0);
  1625.    if(!async_carrier(port))
  1626.      {
  1627.       return(0);
  1628.      }
  1629.   }
  1630.  
  1631. return(1);
  1632.  
  1633.  
  1634. }
  1635. GetNewPosition()
  1636. {
  1637.     unsigned char c=0;
  1638.     struct _block_header block_header;
  1639.     long t1,t2;
  1640.  /* This routine retreives the new file position from
  1641.     the receiver when a REPOS is requested. Its returns 1 if
  1642.     it got the block header and 0 if it didn't.
  1643.  
  1644.     In this driver, the return code is only used if in ACK required
  1645.     mode.*/
  1646.  
  1647.         if(get_block_header(&block_header))
  1648.         {
  1649.  
  1650.               /* There really isn't any need to validate
  1651.                  the file position since the block function is
  1652.                  protected with its own 32 bit CRC. The likely
  1653.                  hood of it being incorrect is so remote....*/
  1654.  
  1655.               /*
  1656.                  One bad aspect to a streamed protocol is the
  1657.                  possiblity of a HUGE amount of data being in
  1658.                  the stream. In the tx buffer, the modem's
  1659.                  tx buffer, on the actual phone line, and if a
  1660.                  network or satellite link is involved that
  1661.                  can add even more.
  1662.  
  1663.                  I've seen the sender as far as 8K ahead of
  1664.                  the receiver and at 2400 baud, that would
  1665.                  take awhile to clear out before the resent
  1666.                  block would ever make it there.
  1667.  
  1668.                  This can make resyncing difficult to do as
  1669.                  well as time consuming. Especially if the
  1670.                  sender miss the first resend request. HST's
  1671.                  and Telebits being half duplex sometimes don't
  1672.                  work well when your pushing them near the
  1673.                  maximum.
  1674.  
  1675.                  In order to get the resyncs to work 100 percent
  1676.                  of the time and as quickly as possible, complex
  1677.                  resend request and verfication routines have to be
  1678.                  used, complex compared to most protocols.
  1679.  
  1680.                  Here you'll find that the sender once he's received
  1681.                  the resend request is required to send the receiver
  1682.                  an acknowledgement that he HAS processed it.
  1683.  
  1684.                  The acknowledgement will consist of 4 bytes arranged
  1685.                  so that the likely hood of running across the same
  1686.                  pattern in the actual file data is small.
  1687.  
  1688.                  The sender MUST wait until the receiver gives the
  1689.                  all clear to resume sending. This helps keep both
  1690.                  sides in sync with each other.
  1691.  
  1692.                  If the sender doesn't get the OK to resume sending
  1693.                  within 60 seconds, we must assume that the receiver
  1694.                  has hung or there is so much line static that there
  1695.                  isn't much hope of resuming. Our only recourse at
  1696.                  that point is to drop carrier.
  1697.  
  1698.                                                           */
  1699.               file_position = block_header.position;
  1700.                                 com_putc(ACK);/* 4 byte seq. to
  1701.                                                    signal recevier
  1702.                                                    that repos was
  1703.                                                    received ok */
  1704.                                 com_putc('*');
  1705.                                 com_putc(ACK);
  1706.                                 com_putc('*');
  1707.               curlocat(7,28);
  1708.               sprintf(junk_string,"REPOS %ld",file_position);
  1709.               colrprtf(0,0,7,"%-40s",junk_string);
  1710.               curlocat(5,58);
  1711.               colrprtf(0,0,7,"%d",++total_errors);
  1712.               if(total_errors > 1 && block_len > 128)
  1713.                                          block_len >>= 1;
  1714.               if(block_len == 128 && !acks_required)
  1715.                                          acks_required = 1;
  1716.               t1 = timerset(6000L);
  1717.               t2 = timerset(200L);/* given the possiblity that
  1718.                                      the receiver sent more than
  1719.                                      one resend request and we
  1720.                                      missed the first,  resend
  1721.                                      the resync acknowledgement no
  1722.                                      closer than 2 seconds apart.
  1723.                                      Anything received  before
  1724.                                      that time we'll ignore.
  1725.                                      */
  1726.  
  1727.               while(!timeup(t1))
  1728.                {
  1729.                 c = com_getc(1);
  1730.                 if(c == 'C' && timeup(t2))
  1731.                  {
  1732.                  /* Must have missed it, send the
  1733.                                 resync acknowledgement again */
  1734.                                 com_putc(ACK);
  1735.                                 com_putc('*');
  1736.                                 com_putc(ACK);
  1737.                                 com_putc('*');
  1738.                                 t2 = timerset(200L);
  1739.                  }
  1740.                  if(c == SOH) return(1);
  1741.  
  1742.                } /* end t1 time loop */
  1743.                /* Receiver possible hung or lines are just flat to bad*/
  1744.                async_dtr(port,0);
  1745.         }
  1746.         sprintf(junk_string,"Bad Blk Header");
  1747.         colrprtf(0,0,7,"%-40s",junk_string);
  1748.         curlocat(5,58);
  1749. return(0);       
  1750.  
  1751. }
  1752.