home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / JBCOMM50.ZIP / MODEM7.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1988-11-26  |  30.4 KB  |  1,314 lines

  1. unit modem7;
  2.  
  3. interface
  4.  
  5. uses jbcomm,dos;
  6.  
  7. const
  8.      bbsname  : string = 'MULTI-BBS            ';
  9.  
  10. type filestr  = string[20];
  11.      fileptr  = ^filetype;
  12.      filetype = record
  13.                                     name : filestr;
  14.                                     nxt  : fileptr
  15.                                 end;
  16.      xfertype = (xmodem_chk,xmodem_crc,telink,modem7_chk,
  17.                                  modem7_crc,ymodem,ymodem_batch);
  18.  
  19.  
  20. function  tmodem7(cp:porttype;path:comstr;transfer:xfertype):word;
  21. function  rmodem7(cp:porttype;path:comstr;transfer:xfertype):word;
  22. procedure addfile(cp:porttype;name:filestr);
  23. function  getfile(cp:porttype):filestr;
  24.  
  25. implementation
  26.  
  27. const
  28.   SOH          = ^A;
  29.   STX          = ^B;
  30.   EOT          = ^D;
  31.     ACK          = ^F;
  32.   BS           = ^H;
  33.     NAK          = ^U;
  34.   SYN          = ^V;
  35.   CAN          = ^X;
  36.     SUB          = ^Z;
  37.  
  38.     timeout      = -1;
  39.     one_second   = 1000;
  40.     two_seconds  = 2*one_second;
  41.   five_seconds = 5*one_second;
  42.     ten_seconds  = 10*one_second;
  43.  
  44. var head, tail : array [porttype] of fileptr;
  45.  
  46. procedure addfile(cp:porttype;name:filestr);
  47. var newname : fileptr;
  48. begin
  49.     new(newname);
  50.     if head[cp]=nil then head[cp]:=newname
  51.     else tail[cp]^.nxt:=newname;
  52.     newname^.name:=name; newname^.nxt:=nil;
  53.     tail[cp]:=newname
  54. end;
  55.  
  56. function getfile(cp:porttype):filestr;
  57. var getname : fileptr;
  58. begin
  59.     if head[cp]<>nil then
  60.     begin
  61.         getname:=head[cp];head[cp]:=head[cp]^.nxt;
  62.         getfile:=getname^.name;dispose(getname)
  63.     end
  64.     else getfile:=''
  65. end;
  66.  
  67.  
  68. function tmodem7;
  69. type memarray    = array [0..65000] of char;
  70. const max_read_size = 8192;
  71.  
  72. var xfile       : file;
  73.     read_buffer : ^memarray;
  74.     file_entry  : searchrec;
  75.     new_header_ch,
  76.     header_ch   : char;
  77.     block       : array [1..2048] of char;
  78.         long_buffer,
  79.         EOF_xfile,
  80.         stop_send   : boolean;
  81.         i,
  82.         buffer_pos,
  83.         buffer_size,
  84.         buffer_length,
  85.         successful,
  86.         recsread,
  87.         max_tries,
  88.         good_blocks,
  89.         bad_blocks,
  90.         bad_threshold,
  91.         block_num,
  92.         block_size,
  93.         block_cnt,
  94.         block_len,
  95.         CRC,
  96.         tries,
  97.     errors      : word;
  98.         inch        : integer;
  99.         filename,
  100.         tname       : filestr;
  101.  
  102.  
  103.   procedure send_xmodem(use_crc:boolean);
  104.  
  105.   var i : word;
  106.  
  107.  
  108.     procedure send_block;
  109.     var i : word;
  110.     begin
  111.             crc:=0;
  112.           tries:=0;
  113.             repeat
  114.                 c_putc(cp,header_ch);
  115.                 c_putc(cp,chr(block_num));
  116.                 c_putc(cp,chr(255-block_num));
  117.                 for i:=1 to block_size do
  118.                 begin
  119.                     c_putc(cp,block[i]);
  120.                     if use_crc then
  121.                         crc:=crc_update(crc,ord(block[i]))
  122.                     else
  123.                         crc:=(crc + ord(block[i])) and 255
  124.                 end;
  125.         if use_crc then
  126.                 begin
  127.                     c_putc(cp,chr(hi(crc)));
  128.                     c_putc(cp,chr(lo(crc)))
  129.                 end
  130.                 else c_putc(cp,chr(lo(crc)));
  131.                 c_flush_in(cp);
  132.                 inc(tries);
  133.             inch:=c_getb(cp,ten_seconds);
  134.                 if inch=ord(CAN) then inch:=c_getb(cp,ten_seconds);
  135.                 if inch<>ord(ACK) then
  136.             begin
  137.               writeln('No ACK. ');
  138.                     inc(errors)
  139.                 end;
  140.           until (inch=ord(ACK)) or (inch=ord(CAN)) or (tries>max_tries) or stop_send
  141.         end;
  142.  
  143.         procedure send_telink_header;
  144.         var i           : word;
  145.                 old_use_crc : boolean;
  146.         begin
  147.           max_tries:=3;
  148.             old_use_crc:=use_crc;
  149.             use_crc:=false;
  150.             i:=block_size;
  151.             block_size:=128;
  152.             Header_ch:=SYN;
  153.             send_block;
  154.             use_crc:=old_use_crc;
  155.           block_size:=i;
  156.             max_tries:=10;
  157.             if inch=ord(ACK) then
  158.                 writeln('Telink header accepted.')
  159.             else
  160.                 writeln('Telink header not accepted.')
  161.         end;
  162.  
  163.         procedure send_ymodem_header;
  164.         var i          : word;
  165.         begin
  166.           max_tries:=3;
  167.             i:=block_size;
  168.             block_size:=128;
  169.             header_ch:=SOH;
  170.             send_block;
  171.             block_size:=i;
  172.             max_tries:=10;
  173.             if inch=ord(ACK) then
  174.                 writeln('Ymodem header accepted.')
  175.             else
  176.                 writeln('Ymodem header not accepted.')
  177.         end;
  178.  
  179.         procedure cancel_transfer;
  180.         begin
  181.           c_flush_in(cp);
  182.             c_putc(cp,CAN);
  183.             c_putc(cp,CAN);
  184.             c_putc(cp,CAN);
  185.             c_putc(cp,CAN);
  186.             c_putc(cp,CAN);
  187.             c_putc(cp,BS);
  188.             c_putc(cp,BS);
  189.             c_putc(cp,BS);
  190.             c_putc(cp,BS);
  191.             c_putc(cp,BS)
  192.         end;
  193.  
  194.     begin
  195.       case transfer of
  196.             xmodem_chk  : tname:='Xmodem (Checksum)';
  197.             xmodem_CRC  : tname:='Xmodem (CRC)';
  198.             telink      : tname:='* Telink';
  199.             modem7_chk  : tname:='* Modem7 (Checksum)';
  200.             modem7_CRC  : tname:='* Modem7 (CRC)';
  201.             ymodem      : tname:='Ymodem';
  202.             ymodem_batch: tname:='* Ymodem Batch'
  203.         end;
  204.         writeln('Send file '+filename+' using '+tname);
  205.         assign(xfile,path+'\'+filename);
  206.         reset(xfile,1);
  207.         if ioresult<>0 then
  208.         begin
  209.             writeln('Cannot open file to send, transfer cancelled.');
  210.             cancel_transfer;
  211.             exit
  212.         end;
  213.         if transfer in [ymodem,ymodem_batch] then
  214.             block_size:=1024
  215.         else
  216.              block_size:=128;
  217.         max_tries:=20;
  218.         block_num:=0;
  219.         block_cnt:=0;
  220.         errors:=0;
  221.         EOF_xfile:=false;
  222.         stop_send:=false;
  223.         tries:=0;
  224.         write('Waiting for NAK/C ---      '+BS+BS+BS+BS);
  225.         c_flush_in(cp);
  226.         repeat
  227.             inch:=c_getb(cp,ten_seconds);
  228.             if inch=ord(CAN) then inch:=c_getb(cp,ten_seconds);
  229.             inc(tries);
  230.             stop_send:=stop_send or (not c_carrier(cp))
  231.         until (tries>max_tries) or
  232.                     (inch=ord(NAK)) or
  233.                     (inch=ord('C')) or
  234.                     (inch=timeout) or
  235.                     (inch=ord(CAN)) or
  236.                     (inch=-2) or
  237.                     stop_send;
  238.         if (inch=timeout) or
  239.              (inch=-2) or
  240.              (tries>max_tries) or
  241.              (inch=ord(CAN)) then
  242.         begin
  243.             writeln('Not Received          ');
  244.             stop_send:=true
  245.         end
  246.         else if (inch=ord(NAK)) then use_crc:=false
  247.         else if (inch=ord('C')) then use_crc:=true;
  248.         if not stop_send then
  249.         begin
  250.       writeln(' Received         ');
  251.             if transfer in [ymodem,ymodem_batch] then
  252.                 header_ch:=STX
  253.             else
  254.                 header_ch:=SOH;
  255.             new_header_ch:=header_ch;
  256.             if transfer=ymodem_batch then
  257.                 send_ymodem_header
  258.       else if transfer=telink then
  259.                 send_telink_header
  260.         end;
  261.         if use_crc then
  262.             block_len:=block_size+2
  263.         else
  264.             block_len:=block_size+1;
  265.         repeat
  266.             stop_send:=stop_send or (not c_carrier(cp));
  267.             if not stop_send then
  268.             begin
  269.                 header_ch:=new_header_ch;
  270.                 blockread(xfile,block,block_size,recsread);
  271.                 if ioresult<>0 then
  272.                 begin
  273.                     writeln('Cannot read data from file.');
  274.                     stop_send:=true
  275.                 end
  276.                 else if recsread<=0 then EOF_xfile:=true
  277.                 else
  278.                 begin
  279.                     inc(block_num);
  280.                     inc(block_cnt);
  281.                     send_block;
  282.                     if inch=ord(ACK) then
  283.                     begin
  284.                         inc(good_blocks);
  285.                         write('Blocks ',block_cnt:5,13)
  286.                     end
  287.                     else
  288.                     begin
  289.                         writeln('Bad Block');
  290.             inc(bad_blocks);
  291.                         if (bad_threshold*bad_blocks>good_blocks) then
  292.                         begin
  293.                             new_header_ch:=SOH;
  294.                             block_size:=128;
  295.                             if use_crc then
  296.                                 block_len:=block_size+2
  297.                             else
  298.                                 block_len:=block_size+1
  299.                         end
  300.                     end
  301.                 end
  302.             end
  303.         until (EOF_xfile) or (tries=max_tries) or (inch=ord(CAN)) or stop_send;
  304.         if stop_send then
  305.             if c_carrier(cp) then cancel_transfer;
  306.         if tries>=max_tries then
  307.             writeln('No ACK ever received.')
  308.         else if inch=ord(CAN) then
  309.             writeln('Receiver cancelled transmission.')
  310.         else if not stop_send then
  311.         begin
  312.             write('Waiting for ACK on EOT ---     '+BS+BS+BS+BS);
  313.             tries:=0;
  314.             repeat
  315.                 c_putc(cp,EOT);
  316.                 inc(tries);
  317.                 inch:=c_getb(cp,ten_seconds);
  318.                 if inch=ord(CAN) then inch:=c_getb(cp,ten_seconds);
  319.                 stop_send:=stop_send or (inch=-2)
  320.       until (inch=ord(ACK)) or
  321.                         (tries=max_tries) or
  322.                         (inch=ord(CAN)) or
  323.                         stop_send;
  324.             if tries=max_tries then
  325.                 writeln('Not Received.')
  326.             else if (inch=ord(CAN)) then
  327.                 writeln('Receiver Cancelled.')
  328.             else if (stop_send) then
  329.                 writeln('Transfer Cancelled.')
  330.             else
  331.             begin
  332.                 writeln('Received.');
  333.                 writeln('  Sent file '+filename);
  334.                 inc(successful)
  335.             end
  336.     end;
  337.         close(xfile)
  338.     end;
  339.  
  340.  
  341.   procedure send_ymodem;
  342.  
  343.     procedure get_unix_style_date(var date : longint;
  344.                                                                   year,
  345.                                                                     month,
  346.                                                                     day,
  347.                                                                     hour,
  348.                                                                     mins,
  349.                                                                     secs : word);
  350.  
  351.       const secs_per_year      = 31536000;
  352.                     secs_per_leap_year = 31622400;
  353.                     secs_per_day       = 86400;
  354.                     secs_per_hour      = 3600;
  355.                     secs_per_minute    = 60;
  356.                     GMT_difference     = -7;
  357.  
  358.       var rdate,
  359.                 t         : longint;
  360.                 leap_year : boolean;
  361.                 i         : word;
  362.  
  363.         const
  364.                 days_per_month: array [1..12] of byte =
  365.                     (31,28,31,30,31,30,31,31,30,31,30,31);
  366.  
  367.       begin
  368.         date:=GMT_difference * secs_per_hour;
  369.             for i:=1970 to (year-1) do
  370.             begin
  371.                 if (i mod 4)=0 then
  372.                     t:=secs_per_leap_year
  373.                 else
  374.                     t:=secs_per_year;
  375.                 date:=date+t
  376.             end;
  377.             if (year mod 4)=0 then
  378.                 days_per_month[2]:=29
  379.             else
  380.                 days_per_month[2]:=28;
  381.             for i:=1 to month-1 do
  382.                 date:=date+days_per_month[i]*secs_per_day;
  383.             date:=date+(day-1)*secs_per_day+
  384.                                                  hour*secs_per_hour+
  385.                                                  mins*secs_per_minute+secs
  386.       end;
  387.  
  388.  
  389.       procedure make_ymodem_header;
  390.         var i,
  391.                 j,
  392.                 k,
  393.                 l,
  394.                 crc   : word;
  395.                 inch  : integer;
  396.                 remo,
  397.                 quot,
  398.                 date  : longint;
  399.                 C_file_size,
  400.                 octd  : string[20];
  401.                 fdate : datetime;
  402.  
  403.         function lowercase(c:char):char;
  404.             begin
  405.                 if c in ['A'..'Z'] then
  406.                     lowercase:=chr(ord(c)+32)
  407.                 else
  408.                     lowercase:=c
  409.             end;
  410.  
  411.       begin
  412.             fillchar(block,130,#0);
  413.         l:=length(filename);
  414.             for i:=1 to l do block[i]:=lowercase(filename[i]);
  415.         str(file_entry.size:10,c_file_size);
  416.             j:=1;
  417.             while(C_file_size[j]=' ') do inc(j);
  418.             i:=l+2;
  419.             for k:=j to 10 do
  420.             begin
  421.                 block[i]:=c_file_size[k];
  422.                 inc(i)
  423.             end;
  424.         unpacktime(file_entry.time,fdate);
  425.             with fdate do get_unix_style_date(date,year,month,day,hour,min,sec);
  426.         octd:='';
  427.             repeat
  428.                 quot:=date div 8;
  429.                 remo:=date-8*quot;
  430.                 octd:=chr(remo+ord('0'))+octd;
  431.                 date:=quot
  432.             until date<=0;
  433.             block[i]:=' ';
  434.             for k:=1 to length(octd) do
  435.             begin
  436.             inc(i);
  437.                 block[i]:=octd[k]
  438.             end
  439.         end;
  440.  
  441.     procedure send_null_file_name;
  442.         var i : word;
  443.         begin
  444.             repeat
  445.                 inch:=c_getb(cp,one_second)
  446.             until (inch=timeout);
  447.             c_putc(cp,SOH);
  448.             c_putc(cp,#0);
  449.             c_putc(cp,#255);
  450.             for i:=1 to 130 do c_putc(cp,#0);
  451.             writeln('Sending Null file name to terminate batch transfer...');
  452.             inch:=c_getb(cp,ten_seconds);
  453.             if(inch=ord(ACK)) then
  454.             begin
  455.                 writeln('');
  456.                 writeln('  Receiver ACKnowledged end of batch.')
  457.             end
  458.         end;
  459.  
  460.   begin
  461.         writeln('Batch file upload using Ymodem.');
  462.         filename:=getfile(cp);
  463.     stop_send:=(filename='');
  464.         if stop_send then
  465.             writeln('No files to send.');
  466.         while not stop_send do
  467.         begin
  468.             findfirst(filename,32,file_entry);
  469.             if doserror=0 then
  470.             begin
  471.                 if not stop_send then make_ymodem_header;
  472.                 if not stop_send then
  473.                 begin
  474.                     writeln('Uploading: '+filename);
  475.                     send_xmodem(true)
  476.                 end
  477.             end;
  478.       filename:=getfile(cp);
  479.             stop_send:=stop_send or (filename='')
  480.         end;
  481.         send_null_file_name;
  482.         writeln('Ymodem batch transfer complete.');
  483.     end;
  484.  
  485.   procedure send_modem7(use_crc:boolean);
  486.     var checksum : word;
  487.             ack_ok   : boolean;
  488.  
  489.       procedure make_telink_header;
  490.         var i,
  491.                 j,
  492.                 l        : word;
  493.                 inch     : integer;
  494.         begin
  495.           fillchar(block,130,#0);
  496.             meml[seg(block):ofs(block[1])]:=file_entry.size;
  497.             meml[seg(block):ofs(block[5])]:=file_entry.time;
  498.             l:=length(filename);
  499.             for i:=1 to l do block[i+8]:=filename[i];
  500.             for i:=(l+1) to 16 do block[i+8]:=' ';
  501.             move(bbsname[1],block[26],16)
  502.         end;
  503.  
  504.       procedure wait_for_NAK;
  505.         begin
  506.             i:=0;
  507.             repeat
  508.                 inch:=c_getb(cp,one_second);
  509.                 inc(i)
  510.             until (inch=ord(NAK)) or
  511.                         (i>=60) or
  512.                         stop_send;
  513.             if inch<>ord(NAK) then
  514.             begin
  515.                 stop_send:=true;
  516.                 writeln('   NAK for start of file name not received;');
  517.                 writeln('   Received Ascii ',inch:4,' instead.')
  518.             end
  519.             else
  520.             begin
  521.                 writeln('   NAK for start of file name received.');
  522.                 c_putc(cp,ACK)
  523.             end;
  524.             c_flush_in(cp)
  525.         end;
  526.  
  527.     procedure send_file_name;
  528.         var modem7_name : string[11];
  529.                 p           : byte;
  530.         begin
  531.       fillchar(modem7_name[1],11,#32);
  532.             p:=pos('.',filename);
  533.             if p>0 then
  534.             begin
  535.                 move(filename[1],modem7_name[1],p-1);
  536.                 move(filename[p+1],modem7_name[9],ord(filename[0])-p)
  537.             end
  538.             else move(filename[1],modem7_name[1],ord(filename[0]));
  539.             i:=0;
  540.             checksum:=0;
  541.             while(not stop_send) and (i<11) do
  542.             begin
  543.                 inc(i);
  544.                 checksum:=(checksum+ord(modem7_name[i])) mod 256;
  545.                 c_putc(cp,modem7_name[i]);
  546.                 inch:=c_getb(cp,ten_seconds);
  547.                 ack_ok:=(inch=ord(ACK));
  548.                 stop_send:=stop_send or (not ack_ok)
  549.             end;
  550.             if not stop_send then
  551.             begin
  552.                 checksum:=(checksum+ord(SUB)) mod 256;
  553.                 c_putc(cp,SUB);
  554.                 inch:=c_getb(cp,ten_seconds);
  555.                 if inch<>checksum then
  556.                 begin
  557.                     stop_send:=true;
  558.                     writeln('   Received checksum for file name not correct;');
  559.                     writeln('   Correct checksum = ',checksum:6,', received ',inch:6)
  560.                 end
  561.                 else c_putc(cp,ACK)
  562.             end
  563.         end;
  564.  
  565.   begin
  566.         case transfer of
  567.             telink     : tname:='* Telink';
  568.             modem7_chk : tname:='* Modem7 (checksum)';
  569.             modem7_crc : tname:='* Modem7 (CRC)'
  570.         end;
  571.     use_crc:=use_crc or (transfer=telink);
  572.         writeln('Batch file upload using '+tname);
  573.         filename:=getfile(cp);
  574.         stop_send:=filename='';
  575.         if stop_send then
  576.             writeln('No files found to send.');
  577.         while not stop_send do
  578.         begin
  579.             findfirst(filename,32,file_entry);
  580.             if doserror=0 then
  581.             begin
  582.         if not stop_send then wait_for_nak;
  583.                 if not stop_send then send_file_name;
  584.                 if not stop_send then
  585.                 begin
  586.                     if transfer=telink then make_telink_header;
  587.                     if not stop_send then send_xmodem(use_crc)
  588.                 end
  589.             end;
  590.             filename:=getfile(cp);
  591.             stop_send:=stop_send or (filename='')
  592.         end;
  593.         c_putc(cp,EOT);
  594.         inch:=c_getb(cp,500);
  595.         if inch=ord(ACK) then
  596.             writeln('  Receiver ACKnowledged EOT.');
  597.     end;
  598.  
  599. begin
  600.   successful:=0;
  601.   case transfer of
  602.         xmodem_chk   :begin
  603.                                       filename:=getfile(cp);
  604.                                       send_xmodem(false)
  605.                                   end;
  606.         xmodem_crc   :begin
  607.                                       filename:=getfile(cp);
  608.                                       send_xmodem(true)
  609.                                   end;
  610.         telink       :send_modem7(true);
  611.         modem7_chk   :send_modem7(false);
  612.         modem7_crc   :send_modem7(true);
  613.         ymodem       :begin
  614.                                       filename:=getfile(cp);
  615.                                       send_xmodem(true)
  616.                                   end;
  617.         ymodem_batch :send_ymodem
  618.     end;
  619.     tmodem7:=successful
  620. end;
  621.  
  622.  
  623. function rmodem7;
  624.  
  625. type memarray    = array [0..65000] of char;
  626.  
  627. const max_write_buffer = 2048;
  628.  
  629. var block        : array [1..2048] of char;
  630.     file_entry   : searchrec;
  631.         null_file_name,
  632.         stop_receive : boolean;
  633.         filename     : filestr;
  634.         block_num    : byte;
  635.         write_buffer : ^memarray;
  636.         successful   : word;
  637.  
  638.  
  639.   procedure receive_xmodem(use_crc:boolean);
  640.  
  641.     const max_errors = 20;
  642.  
  643.   var
  644.         block_count,
  645.         i,
  646.         error_count,
  647.         inch,
  648.         ch,
  649.         block_len,
  650.         blockl_errors,
  651.         SOH_errors,
  652.         blockn_errors,
  653.         comple_errors,
  654.         timeout_errors,
  655.         resend_errors,
  656.         CRC_errors,
  657.         crc_tries,
  658.         SOH_time,
  659.         write_count,
  660.         err,
  661.         buffer_pos,
  662.         blocks_to_get,
  663.         buffer_length   : integer;
  664.         block_comp,
  665.         block_prev,
  666.         block_prev1     : byte;
  667.         error_flag,
  668.         truncate_file,
  669.         RFile_open,
  670.         OK_transfer,
  671.         block_zero,
  672.         Use_crc_2,
  673.         long_buffer     : boolean;
  674.         rfile_name,
  675.         tname           : string;
  676.         rfile_size_2,
  677.         rfile_size      : longint;
  678.         xfile           : file;
  679.  
  680.  
  681.     procedure open_receiving_file;
  682.         begin
  683.             if filename='' then filename:=getfile(cp);
  684.             if not rfile_open then
  685.             begin
  686.                 assign(xfile,path+'\'+filename);
  687.                 rewrite(xfile,1);
  688.                 if ioresult<>0 then
  689.                 begin
  690.                     writeln('Cannot open specified file for reception.');
  691.                     stop_receive:=true
  692.                 end
  693.                 else rfile_open:=true
  694.             end;
  695.             if rfile_open then writeln('Receiving file '+filename)
  696.         end;
  697.  
  698.     function receive_block(use_crc:boolean):boolean;
  699.  
  700.     var crc,
  701.                 checksum,
  702.                 i         : word;
  703.         begin
  704.             receive_block:=false;
  705.             checksum:=0;
  706.             crc:=0;
  707.             for i:=1 to block_len do
  708.             begin
  709.                 ch:=c_getb(cp,one_second);
  710.                 if ch=timeout then
  711.                 begin
  712.                     inc(blockl_errors);
  713.                     writeln('Block Length Error.')
  714.                 end;
  715.                 block[i]:=chr(ch);
  716.                 if use_crc then
  717.                     crc:=crc_update(crc,ch)
  718.                 else
  719.           checksum:=(checksum+ch) and 255
  720.             end;
  721.             if use_crc then
  722.             begin
  723.                 ch:=c_getb(cp,one_second);
  724.                 if ch<>timeout then
  725.                 begin
  726.                     crc:=CRC_update(CRC,ch);
  727.                     ch:=c_getb(cp,one_second);
  728.           if ch<>timeout then
  729.                     begin
  730.                         crc:=CRC_update(crc,ch);
  731.                         receive_block:=(crc=0)
  732.                     end
  733.                     else
  734.                     begin
  735.             inc(blockl_errors);
  736.                         writeln('Block Length Error ',blockl_errors:5)
  737.                     end
  738.                 end
  739.                 else
  740.                 begin
  741.                     inc(blockl_errors);
  742.                     writeln('Block Length Error ',blockl_errors:5)
  743.                 end
  744.             end
  745.             else
  746.             begin
  747.                 ch:=c_getb(cp,one_second);
  748.                 receive_block:=(checksum=ch)
  749.             end
  750.         end;
  751.  
  752.       procedure receive_telink_header;
  753.         var i : word;
  754.         begin
  755.       rfile_size:=0;
  756.             rfile_name:='';
  757.             for i:=4 downto 1 do
  758.                 rfile_size:=rfile_size*256+ord(block[i]);
  759.             blocks_to_get:=round((rfile_size div 128)+0.49);
  760.             for i:=9 to 24 do
  761.                 if block[i]<>#0 then
  762.                     rfile_name:=rfile_name+block[i];
  763.       while (length(rfile_name)>0) and
  764.             (rfile_name[length(rfile_name)]=' ') do dec(rfile_name[0]);
  765.             i:=0;
  766.       findfirst(path+rfile_name,readonly+sysfile+hidden+archive,file_entry);
  767.             if doserror=0 then
  768.             begin
  769.                 writeln('File collision');
  770.                 repeat
  771.                     rfile_name[length(rfile_name)]:=chr(ord('0')+i);
  772.                     inc(i);
  773.                     findfirst(path+rfile_name,readonly+sysfile+hidden+archive,file_entry)
  774.                 until (doserror<>0) or (i>=10);
  775.                 stop_receive:=(i>=10)
  776.             end;
  777.             if not stop_receive then
  778.             begin
  779.         writeln('File name:           '+filename);
  780.               writeln('File Size in bytes:  ',rfile_size:8);
  781.               writeln('File Size in blocks: ',blocks_to_get:8);
  782.               if rfile_size>0 then truncate_file:=true
  783.             end
  784.       else writeln('Nonrecoverable file collision')
  785.         end;
  786.  
  787.     procedure receive_ymodem_header;
  788.     var i,j    : word;
  789.         begin
  790.             rfile_size:=0;
  791.             rfile_name:='';
  792.       i:=1;
  793.       while(block[i]<>#0) do
  794.             begin
  795.                 rfile_name:=rfile_name+upcase(block[i]);
  796.                 inc(i)
  797.             end;
  798.       if rfile_name='' then
  799.             begin
  800.                 null_file_name:=true;
  801.                 exit
  802.             end;
  803.             inc(i);
  804.             while(block[i]<>#0) and (block[i]<>' ') do
  805.             begin
  806.                 rfile_size:=rfile_size*10+ord(block[i])-ord('0');
  807.                 inc(i)
  808.             end;
  809.             inc(i);
  810.             while (block[i]<>#0) and (block[i]<>' ') do inc(i);
  811.             j:=0;
  812.       findfirst(path+rfile_name,readonly+sysfile+hidden+archive,file_entry);
  813.             if doserror=0 then
  814.             begin
  815.                 writeln('File collision');
  816.                 repeat
  817.                     rfile_name[length(rfile_name)]:=chr(ord('0')+j);
  818.                     inc(j);
  819.                     findfirst(path+rfile_name,readonly+sysfile+hidden+archive,file_entry)
  820.                 until (doserror<>0) or (j>=10);
  821.                 stop_receive:=(j>=10)
  822.             end;
  823.             filename:=rfile_name;
  824.             if not stop_receive then
  825.             begin
  826.               writeln(' File name:              '+filename);
  827.         blocks_to_get:=round(rfile_size/1024+0.49);
  828.                 if rfile_size>0 then
  829.                 begin
  830.           writeln(' File size in bytes:     ',rfile_size:8);
  831.                     writeln(' File size in 1K blocks: ',blocks_to_get:8)
  832.                 end;
  833.                 blocks_to_get:=round(rfile_size/128+0.49);
  834.         if rfile_size>0 then truncate_file:=true;
  835.                 open_receiving_file
  836.             end
  837.         end;
  838.  
  839.     procedure wait_for_soh(wait_time:word;var inch:integer);
  840.     var itime : word;
  841.         begin
  842.             inch:=timeout;
  843.             if stop_receive then exit;
  844.             itime:=0;
  845.             repeat
  846.                 inc(itime);
  847.                 inch:=c_getb(cp,one_second);
  848.                 if not c_carrier(cp) then
  849.                 begin
  850.                     stop_receive:=true;
  851.                     inch:=timeout
  852.                 end
  853.             until (stop_receive or (itime>wait_time) or (inch<>timeout))
  854.         end;
  855.  
  856.     procedure write_file_data;
  857.  
  858.             procedure do_actual_write(write_count:integer);
  859.             begin
  860.                 writeln('Writing.');
  861.                 if((rfile_size_2+write_count)>rfile_size) and truncate_file then
  862.                     write_count:=trunc(rfile_size-rfile_size_2);
  863.                 blockwrite(xfile,write_buffer^,write_count);
  864.                 if (ioresult<>0) then
  865.                 begin
  866.                     writeln('Error writing to disk, transfer cancelled.');
  867.                     stop_receive:=true
  868.                 end;
  869.                 rfile_size_2:=rfile_size_2+write_count
  870.             end;
  871.  
  872.         begin
  873.             if (not long_buffer) then
  874.                 do_actual_write(block_len)
  875.             else
  876.             begin
  877.                 if(buffer_pos+block_len)>max_write_buffer then
  878.                 begin
  879.                     do_actual_write(buffer_pos);
  880.                     buffer_pos:=0
  881.                 end;
  882.                 move(block,write_buffer^[buffer_pos],block_len);
  883.                 buffer_pos:=buffer_pos+block_len
  884.             end
  885.         end;
  886.  
  887.     procedure cancel_transfer;
  888.         begin
  889.             c_flush_in(cp);
  890.             c_putc(cp,CAN);
  891.             c_putc(cp,CAN);
  892.             c_putc(cp,CAN);
  893.             c_putc(cp,CAN);
  894.       c_putc(cp,CAN);
  895.  
  896.       c_putc(cp,BS);
  897.             c_putc(cp,BS);
  898.             c_putc(cp,BS);
  899.             c_putc(cp,BS);
  900.       c_putc(cp,BS)
  901.         end;
  902.  
  903.   begin
  904.     case transfer of
  905.             xmodem_chk      : tname:='Xmodem (checksum)';
  906.             xmodem_CRC      : tname:='Xmodem (CRC)';
  907.             telink          : tname:='Telink';
  908.             modem7_chk      : tname:='Modem7 (checksum)';
  909.             modem7_CRC      : tname:='Modem7 (CRC)';
  910.             ymodem          : tname:='Ymodem';
  911.             ymodem_batch    : tname:='Ymodem Batch'
  912.       end;
  913.         if filename='' then
  914.             writeln('Receive file using '+tname)
  915.         else
  916.             writeln('Receive file '+filename+' using '+tname);
  917.         soh_errors:=0;
  918.         blockl_errors:=0;
  919.         blockn_errors:=0;
  920.         comple_errors:=0;
  921.         timeout_errors:=0;
  922.         resend_errors:=0;
  923.         crc_errors:=0;
  924.     block_num:=0;
  925.         block_count:=0;
  926.         block_prev:=0;
  927.         block_len:=128;
  928.         error_count:=0;
  929.         crc_tries:=0;
  930.         soh_time:=10;
  931.         truncate_file:=false;
  932.         rfile_size:=0;
  933.         rfile_size_2:=0;
  934.     rfile_name:='';
  935.         ok_transfer:=false;
  936.         block_zero:=false;
  937.     stop_receive:=false;
  938.         null_file_name:=false;
  939.         if (max_write_buffer>1024) and
  940.              (max_write_buffer<maxavail) then
  941.         begin
  942.             buffer_length:=max_write_buffer;
  943.             long_buffer:=true;
  944.             getmem(write_buffer,buffer_length)
  945.         end
  946.         else
  947.         begin
  948.             long_buffer:=false;
  949.             buffer_length:=1024;
  950.             write_buffer:=@block
  951.         end;
  952.         buffer_pos:=0;
  953.         rfile_open:=false;
  954.         if filename<>'' then
  955.         begin
  956.             open_receiving_file;
  957.             if stop_receive  then
  958.             begin
  959.                 cancel_transfer;
  960.                 exit
  961.             end
  962.         end
  963.         else if (filename='') and
  964.                  (transfer in [xmodem_chk,xmodem_crc,ymodem]) then
  965.              open_receiving_file;
  966.         repeat
  967.             error_flag:=false;
  968.       repeat
  969.                 if block_count=0 then
  970.                 begin
  971.                     use_crc:=use_crc and (crc_tries<4);
  972.                     c_flush_in(cp);
  973.                     if use_crc then
  974.                         c_putc(cp,'C')
  975.                     else
  976.                       c_putc(cp,NAK);
  977.                     inc(crc_tries);
  978.                 end;
  979.                 wait_for_soh(soh_time,inch);
  980.                 if inch=ord(CAN) then
  981.                     wait_for_soh(soh_time,inch)
  982.             until (inch=ord(SOH)) or
  983.                         (inch=ord(EOT)) or
  984.                         (inch=ord(CAN)) or
  985.                         (inch=ord(SYN)) or
  986.                         (inch=ord(STX)) or
  987.                         (inch=timeout)       or
  988.                         (error_count>max_errors) or
  989.                         (stop_receive);
  990.             if stop_receive then
  991.             begin
  992.                 if not c_carrier(cp) then
  993.                 begin
  994.                     writeln('Carrier Dropped.');
  995.                 end
  996.             end
  997.             else
  998.             begin
  999.                 if inch=timeout then
  1000.                 begin
  1001.                     inc(timeout_errors);
  1002.                     writeln('Timeout Errors ',timeout_errors:5)
  1003.                 end
  1004.                 else
  1005.                 begin
  1006.                     if (inch=ord(SOH)) or
  1007.                          (inch=ord(SYN)) or
  1008.                          (inch=ord(STX)) then
  1009.                     begin
  1010.                         if inch=ord(STX) then
  1011.                             block_len:=1024
  1012.                         else
  1013.                             block_len:=128;
  1014.                         ch:=c_getb(cp,one_second);
  1015.                         if ch=timeout then
  1016.                         begin
  1017.                             inc(blockl_errors);
  1018.                             writeln('Short Block')
  1019.                         end;
  1020.                         block_num:=ch;
  1021.                         ch:=c_getb(cp,one_second);
  1022.                         if ch=timeout then
  1023.                         begin
  1024.                             inc(blockl_errors);
  1025.                             writeln('Short Block')
  1026.                         end;
  1027.                         block_comp:=ch;
  1028.                         if ((block_num+block_comp)=255) then
  1029.                         begin
  1030.                             block_prev1:=block_prev+1;
  1031.                             block_zero:=(block_count=0) and
  1032.                                                     (block_num=0)   and
  1033.                                                     ((inch=ord(SYN)) or
  1034.                                                     (transfer in [ymodem,ymodem_batch]));
  1035.                             if (block_num=block_prev1) or block_zero then
  1036.                             begin
  1037.                                 use_crc_2:=use_crc and (not (block_zero and (transfer=telink)));
  1038.                                 if receive_block(use_crc_2) then
  1039.                                 begin
  1040.                                     if (not block_zero) then
  1041.                                     begin
  1042.                                         write_file_data;
  1043.                                         error_count:=0;
  1044.                                         inc(block_count);
  1045.                                         write('Block ',block_count:5,#13);
  1046.                                         block_prev:=block_num;
  1047.                                         c_putc(cp,ACK)
  1048.                                     end
  1049.                                     else
  1050.                                     begin
  1051.                                         if inch=ord(SYN) then
  1052.                                             receive_telink_header
  1053.                                         else if (transfer in [Ymodem,Ymodem_batch]) then
  1054.                                                  receive_ymodem_header;
  1055.                                         if not stop_receive then
  1056.                                         begin
  1057.                                             c_putc(cp,ACK);
  1058.                                             error_count:=0
  1059.                                         end
  1060.                                     end
  1061.                                 end
  1062.                                 else
  1063.                                 begin
  1064.                                     inc(crc_errors);
  1065.                                     if use_crc then
  1066.                                       writeln('CRC error ',crc_errors:5)
  1067.                                     else
  1068.                                         writeln('Checksum error ',crc_errors:5)
  1069.                                 end
  1070.                           end
  1071.                             else
  1072.                             begin
  1073.                                 if (block_num=block_prev) then
  1074.                                 begin
  1075.                                     inc(resend_errors);
  1076.                                     writeln('Duplicate Block ',resend_errors:5);
  1077.                                     c_putc(cp,ACK)
  1078.                                 end
  1079.                                 else
  1080.                                 begin
  1081.                                     inc(blockn_errors);
  1082.                                     writeln('Synchronization Error ',blockn_errors:5)
  1083.                                 end
  1084.                     end
  1085.                         end
  1086.                       else
  1087.                       begin
  1088.                           inc(comple_errors);
  1089.                           writeln('Sector Number error ',comple_errors:5)
  1090.                       end
  1091.                   end
  1092.             else
  1093.                   begin
  1094.                         if (inch<>ord(EOT)) then
  1095.                         begin
  1096.                             inc(soh_errors);
  1097.                             writeln('SOH error ',soh_errors:5);
  1098.                         end
  1099.                     end;
  1100.                     if error_flag then
  1101.                     begin
  1102.                         inc(error_count);
  1103.                         c_flush_in(cp);
  1104.                         c_putc(cp,NAK)
  1105.                     end
  1106.         end
  1107.             end
  1108.     until (inch=ord(EOT)    ) or
  1109.                     (inch=ord(CAN)    ) or
  1110.                     (stop_receive     ) or
  1111.                     (null_file_name   ) or
  1112.                     (error_count>max_errors);
  1113.         if stop_receive then
  1114.             cancel_transfer
  1115.         else
  1116.         begin
  1117.             if null_file_name then
  1118.             begin
  1119.                 writeln('Null file name received.')
  1120.             end
  1121.             else
  1122.             begin
  1123.                 if (inch=ord(EOT)) and (error_count<=max_errors) then
  1124.                 begin
  1125.                     c_putc(cp,ACK);
  1126.                     if buffer_pos>0 then
  1127.                     begin
  1128.                         write_count:=buffer_pos;
  1129.                         if((rfile_size_2+write_count)>rfile_size) and truncate_file then
  1130.                             write_count:=trunc(rfile_size-rfile_size_2);
  1131.                         blockwrite(xfile,write_buffer^,write_count);
  1132.                         if ioresult<>0 then
  1133.                         begin
  1134.                             writeln('Error in writing to disk, file may be bad.');
  1135.                         end;
  1136.                         rfile_size_2:=rfile_size_2+write_count
  1137.                   end;
  1138.                     writeln('Transfer Complete; ');
  1139.                     if rfile_size>0 then
  1140.                         if rfile_size<=rfile_size_2 then
  1141.                           rfile_size_2:=rfile_size;
  1142.                     inc(successful);
  1143.                     ok_transfer:=true;
  1144.                     writeln('Received file '+filename);
  1145.                     addfile(cp,filename)
  1146.                 end
  1147.                 else
  1148.                 begin
  1149.                     if (inch=ord(CAN)) then
  1150.                         writeln('Transmitter cancelled file transfer.')
  1151.                 else
  1152.                     writeln('Transfer cancelled.')
  1153.                 end
  1154.             end
  1155.         end;
  1156.         close(xfile);
  1157.         if long_buffer then freemem(write_buffer,buffer_length)
  1158.     end;
  1159.  
  1160.   procedure receive_ymodem;
  1161.     begin
  1162.         stop_receive:=false;
  1163.         null_file_name:=false;
  1164.         while((not stop_receive) and (not null_file_name)) do
  1165.         begin
  1166.             filename:='';
  1167.             receive_xmodem(true);
  1168.             if ((not null_file_name) and (not stop_receive)) then
  1169.                 writeln('  Received file: '+filename)
  1170.         end;
  1171.         if null_file_name then
  1172.         begin
  1173.             writeln('  Received null file name from sender.')
  1174.         end
  1175.     end;
  1176.  
  1177.  
  1178.   procedure receive_modem7(use_crc:boolean);
  1179.     const
  1180.         maxtry =5;
  1181.         maxnoise=10;
  1182.  
  1183.   var
  1184.         rfilename : string;
  1185.         inch,
  1186.         inch_save,
  1187.         checksum,
  1188.         i,
  1189.         j,
  1190.         tries,
  1191.         ntries    : integer;
  1192.         ch        : char;
  1193.         endfname  : boolean;
  1194.         tname     : string[10];
  1195.  
  1196.   begin
  1197.         case transfer of
  1198.             telink     : tname:='Telink';
  1199.             modem7_chk : tname:='Modem7 (checksum)';
  1200.             modem7_crc : tname:='Modem7 (CRC)'
  1201.         end;
  1202.         use_crc:=use_crc or (transfer=telink);
  1203.         writeln('Batch receive using '+tname);
  1204.         stop_receive:=false;
  1205.         tries:=0;
  1206.         c_flush_in(cp);
  1207.         repeat
  1208.             checksum:=0;
  1209.             rfilename:='';
  1210.             repeat
  1211.                 c_putc(cp,NAK);
  1212.                 ntries:=0;
  1213.                 repeat
  1214.                     inch:=c_getb(cp,200);
  1215.                     inc(ntries)
  1216.                 until (ntries>maxnoise) or
  1217.                             (inch<=127) or
  1218.                             stop_receive;
  1219.               inc(tries)
  1220.             until(inch=ord(ACK)) or
  1221.                      (inch=ord(EOT)) or
  1222.                      (inch=ord(CAN)) or
  1223.                      (tries>maxtry) or
  1224.                      stop_receive;
  1225.             stop_receive:=(inch<>ord(ACK)) or stop_receive;
  1226.             inch_save:=inch;
  1227.             if not stop_receive then
  1228.               repeat
  1229.                     inch:=c_getb(cp,500);
  1230.                     endfname:=(inch=ord(CAN)) or
  1231.                                         (inch=ord(EOT)) or
  1232.                                         (inch=timeout) or
  1233.                                         (inch=ord(SUB)) or
  1234.                                         stop_receive;
  1235.                     if not endfname then
  1236.                     begin
  1237.                         c_putc(cp,ACK);
  1238.                         rfilename:=rfilename+chr(inch);
  1239.                         checksum:=(checksum+inch) and 255
  1240.                     end
  1241.         until endfname
  1242.             else
  1243.                 inch:=timeout;
  1244.       if inch=ord(SUB) then
  1245.             begin
  1246.                 checksum:=(checksum+inch) and 255;
  1247.                 c_putc(cp,chr(checksum));
  1248.                 inch:=c_getb(cp,ten_seconds);
  1249.                 if (inch=ord(ACK)) and (not stop_receive) then
  1250.                 begin
  1251.                     for i:=length(rfilename) to 11 do
  1252.                         rfilename:=rfilename+' ';
  1253.                     move(rfilename[9],rfilename[10],3);
  1254.                     rfilename[9]:=' ';
  1255.           while rfilename[1]=' ' do rfilename:=copy(rfilename,2,12);
  1256.           while pos('  ',rfilename)>0 do
  1257.             rfilename:=copy(rfilename,1,pos('  ',rfilename))+
  1258.                        copy(rfilename,pos('  ',rfilename)+1,12);
  1259.                     if pos(' ',filename)>0 then filename[pos(' ',filename)]:='.';
  1260.                     j:=0;
  1261.               findfirst(path+filename,readonly+sysfile+hidden+archive,file_entry);
  1262.                     if doserror=0 then
  1263.                     begin
  1264.                         writeln('File collision');
  1265.                         repeat
  1266.                             filename[length(filename)]:=chr(ord('0')+j);
  1267.                             inc(j);
  1268.                             findfirst(path+filename,readonly+sysfile+hidden+archive,file_entry)
  1269.                         until (doserror<>0) or (j>=10);
  1270.                         stop_receive:=(j>=10)
  1271.                     end;
  1272.                     if not stop_receive then
  1273.                     begin
  1274.                         writeln('  Receiving: '+filename);
  1275.                         receive_xmodem(use_crc)
  1276.                     end
  1277.                 end
  1278.                 else stop_receive:=true
  1279.             end
  1280.             else stop_receive:=true
  1281.         until stop_receive;
  1282.         if inch_save=ord(EOT) then
  1283.         begin
  1284.             c_putc(cp,ACK);
  1285.             writeln('Received EOT from sender.')
  1286.         end
  1287.         else
  1288.         begin
  1289.             writeln('Transfer Cancelled.')
  1290.         end
  1291.     end;
  1292.  
  1293.  
  1294. begin
  1295.   filename:='';
  1296.   successful:=0;
  1297.   case transfer of
  1298.         xmodem_chk   : receive_xmodem(FALSE);
  1299.         xmodem_crc   : receive_xmodem(TRUE);
  1300.         telink       : receive_modem7(TRUE);
  1301.         modem7_chk   : receive_modem7(FALSE);
  1302.         modem7_CRC   : receive_modem7(TRUE);
  1303.         ymodem       : receive_ymodem;
  1304.         ymodem_batch : receive_ymodem
  1305.     end;
  1306.     rmodem7:=successful
  1307. end;
  1308.  
  1309. var i : porttype;
  1310.  
  1311. begin
  1312.   for i:=com0 to com8 do head[i]:=nil
  1313. end.
  1314.