home *** CD-ROM | disk | FTP | other *** search
/ Jason Aller Floppy Collection / 270.img / FORUM25C.ZIP / PROTOCOL.PAS < prev    next >
Pascal/Delphi Source File  |  1988-12-27  |  19KB  |  738 lines

  1. {$R-,S-,I-,D-,V-,B-,N-,L- }
  2. {$O+}
  3.  
  4. { $define testprotocol}  (* Close this define for test mode *)
  5.  
  6. {$ifdef testprotocol}
  7. {*}
  8. {*}uses crt,dos,
  9. {*}     modem;
  10. {*}
  11. {*}{$I-}
  12. {*}type anystr=string[255];
  13. {*}     lstr=string[80];
  14. {*}     mstr=string[30];
  15. {*}     sstr=string[15];
  16. {*}VAR logontime,iocode:integer;
  17. {*}const timer=0; timeleft=1; numminsxfer=1;
  18. {*}Function keyhit:boolean;
  19. {*}begin
  20. {*}  keyhit:=keypressed
  21. {*}end;
  22. {*}Function bioskey:char;
  23. {*}VAR k:char;
  24. {*}begin
  25. {*}  read (kbd,k);
  26. {*}  bioskey:=k
  27. {*}end;
  28. {*}Function hungupon:boolean;
  29. {*}begin
  30. {*}  hungupon:=not carrier
  31. {*}end;
  32. {*}Function strr (n:integer):mstr;
  33. {*}VAR q:mstr;
  34. {*}begin
  35. {*}  str (n,q);
  36. {*}  strr:=q
  37. {*}end;
  38. {*}Function minstr (blocks:integer):mstr;
  39. {*}begin
  40. {*}  minstr:='<'+strr(blocks)+' blocks left>'
  41. {*}end;
  42. {*}Procedure fileerror (s1,s2:lstr);
  43. {*}begin
  44. {*}  writeln ('File error ',s1,' and ',s2);
  45. {*}  halt
  46. {*}end;
  47. {*}Procedure starttimer (q:integer); begin end;
  48. {*}Procedure stoptimer (q:integer); begin end;
  49. {*}Procedure settimeleft (q:integer); begin end;
  50. {*}Procedure splitscreen (y:integer);
  51. {*}begin
  52. {*}  window (1,1,80,y-1)
  53. {*}end;
  54. {*}Procedure top; begin end;
  55. {*}Procedure unsplit;
  56. {*}begin
  57. {*}  window (1,1,80,25)
  58. {*}end;
  59. {*}
  60. {*}
  61. {*}
  62. {*}Function protocolxfer (send,crcmode,ymodem:boolean; fn:lstr):integer;
  63.  
  64. {$else}
  65.  
  66. unit protocol;
  67.  
  68.  
  69. {/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\}
  70.  
  71. interface
  72.  
  73. uses dos,crt,
  74.      gentypes,modem,statret,windows,gensubs,subs1,subs2;
  75.  
  76. {/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\}
  77.  
  78.  
  79. Function protocolxfer (send,crcmode,ymodem:boolean; fn:lstr):integer;
  80. { Return codes:  0=OK, 1=Cancelled within last three blocks, 2=Aborted }
  81.  
  82.  
  83. {/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\}
  84.  
  85. implementation
  86.  
  87. {/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\}
  88.  
  89.  
  90. Function protocolxfer (send,crcmode,ymodem:boolean; fn:lstr):integer;
  91.  
  92. {$endif}
  93.  
  94.   const can=^X; ack=^F; nak=^U; soh=^A; stx=^B; eot=^D; crcstart='C';
  95.  
  96.   VAR timedout:boolean;
  97.  
  98.   Function tenthseconds:integer;
  99.   VAR r:registers;
  100.   begin
  101.     r.ah:=$2c;
  102.     intr ($21,r);
  103.     tenthseconds:=(r.dh*10)+(r.dl div 10)
  104.   end;
  105.  
  106.   Function fromnow (tenths:integer):integer;
  107.   begin
  108.     tenths:=tenthseconds+tenths;
  109.     if tenths>599 then tenths:=tenths-600;
  110.     fromnow:=tenths
  111.   end;
  112.  
  113.   Function timeout (en:integer):boolean;
  114.   begin
  115.     timeout:=(en=tenthseconds) or hungupon
  116.   end;
  117.  
  118.   Procedure clearmodemahead;
  119.   VAR k:char;
  120.   begin
  121.     while numchars>0 do k:=getchar
  122.   end;
  123.  
  124.   Procedure wait (tenths:integer);
  125.   begin
  126.     tenths:=fromnow (tenths);
  127.     repeat until timeout (tenths) or hungupon
  128.   end;
  129.  
  130.   Function waitchar (tenths:integer):char;
  131.   begin
  132.     waitchar:=#0;
  133.     tenths:=fromnow (tenths);
  134.     repeat
  135.       if numchars>0 then begin
  136.         waitchar:=getchar;
  137.         timedout:=false;
  138.         exit
  139.       end
  140.     until timeout (tenths) or hungupon;
  141.     timedout:=true
  142.   end;
  143.  
  144.   Procedure computecrc (VAR block; blocksize:integer; VAR outcrc:word);
  145.   VAR cnt,c2:integer;
  146.       crc,b:word;
  147.       blk:array[1..1030] of byte absolute block;
  148.       willbecarry:boolean;
  149.   begin
  150.     crc:=0;
  151.     for cnt:=1 to blocksize do begin
  152.       b:=blk[cnt];
  153.       for c2:=1 to 8 do begin
  154.         willbecarry:=(crc and $8000)=$8000;
  155.         crc:=(crc shl 1) or (b shr 7);
  156.         b:=(b shl 1) and 255;
  157.         if willbecarry then crc:=crc xor $1021
  158.       end
  159.     end;
  160.     outcrc:=crc
  161.   end;
  162.  
  163. (****
  164.     inline (
  165.              $1E/                    {           PUSH  DS               }
  166.              $C5/$B6/block/          {           LDS   SI,[BP+block]    }
  167.              $8B/$96/blocksize/      {           MOV   DX,[BP+blocksize]}
  168.              $31/$DB/                {           XOR   BX,BX            }
  169.              $FC/                    {           CLD                    }
  170.              $AC/                    { Mainloop: LODSB                  }
  171.              $B9/$08/$00/            {           MOV   CX,0008          }
  172.              $D0/$E0/                { Byteloop: SHL   AL,1             }
  173.              $D1/$D3/                {           RCL   BX,1             }
  174.              $73/$04/                {           JNC   No_xor           }
  175.              $81/$F3/$21/$10/        {           XOR   BX,1021          }
  176.              $E2/$F4/                { No_xor:   LOOP  Byteloop         }
  177.              $4A/                    {           DEC   DX               }
  178.              $75/$ED/                {           JNZ   Mainloop         }
  179.              $89/$9E/crc/            {           MOV   [BP+crc],BX      }
  180.              $1F                     {           POP   DS               }
  181.            );
  182. ****)
  183.  
  184.   Procedure computecksum (VAR data; blocksize:integer; VAR outcksum:byte);
  185.   VAR t:array [1..1024] of byte absolute data;
  186.       cnt,q:integer;
  187.   begin
  188.     q:=0;
  189.     for cnt:=1 to blocksize do q:=q+t[cnt];
  190.     outcksum:=q and 255
  191.   end;
  192.  
  193.   Procedure showerrorstats (curblk,totalerrs,consec:integer);
  194.   VAR x:integer;
  195.       r:real;
  196.   begin
  197.     x:=wherex;
  198.     write (usr,totalerrs);
  199.     gotoxy (x,wherey+1);
  200.     write (usr,consec,' ');
  201.     gotoxy (x,wherey+1);
  202.     if curblk+totalerrs<>0 then begin
  203.       r:=round(10000.0*totalerrs/(curblk+totalerrs))/100.0;
  204.       write (usr,r:0:2,'%    ')
  205.     end
  206.   end;
  207.  
  208.   {overlay} Function xymodemsend (ymodem:boolean):integer;
  209.   VAR f:file;
  210.       b:array [1..1026] of byte;
  211.       blocksize:integer;
  212.       fsize,curblk,totalerrs,consec,blocksatatime:integer;
  213.       k:char;
  214.       firstblock:boolean;
  215.       totaltime:sstr;
  216.  
  217.     Function getctrlchar:char;   { Gets ACK/NAK/CAN }
  218.     VAR k,k2:char;
  219.         cnt:integer;
  220.     begin
  221.       getctrlchar:=can;
  222.       repeat
  223.         cnt:=0;
  224.         repeat
  225.           k:=waitchar (10);
  226.           cnt:=cnt+1;
  227.           if keyhit then begin
  228.             k2:=bioskey;
  229.             if k2=^X then exit;
  230.             timedout:=true
  231.           end
  232.         until (not timedout) or (cnt=60);
  233.         if timedout or hungupon then exit;
  234.         if (k in [ack,nak,crcstart,can]) then begin
  235.           getctrlchar:=k;
  236.           if k=can then sendchar (can);
  237.           exit
  238.         end
  239.       until hungupon;
  240.       timedout:=true
  241.     end;
  242.  
  243.     Procedure sendendoffile;
  244.     VAR k:char;
  245.         tries:integer;
  246.     begin
  247.       tries:=0;
  248.       repeat
  249.         tries:=tries+1;
  250.         sendchar(eot);
  251.         k:=waitchar (20);
  252.       until (k=ack) or (k=can) or (tries=3);
  253.       sendchar(eot)
  254.     end;
  255.  
  256.     Procedure getblockfromfile;
  257.     begin
  258.       fillchar (b,sizeof(b),26);
  259.       blockread (f,b,blocksatatime);
  260.       blocksize:=blocksatatime shl 7
  261.     end;
  262.  
  263.     Procedure buildfirstblock;
  264.     VAR cnt,p:integer;
  265.     begin
  266.       blocksize:=128;
  267.       fillchar(b,128,0);
  268.       p:=length(fn);
  269.       repeat
  270.         p:=p-1
  271.       until (p=0) or (fn[p]='\');
  272.       for cnt:=1 to length(fn)-p do b[cnt]:=ord(fn[cnt+p])
  273.     end;
  274.  
  275.     Procedure sendblock (num:integer);
  276.     VAR cnt,bksize:integer;
  277.         crc:word;
  278.         n:byte;
  279.         k:char;
  280.     begin
  281.       clearmodemahead;
  282.       n:=num and 255;
  283.       if blocksize=1024
  284.         then k:=stx
  285.         else k:=soh;
  286.       if crcmode
  287.         then
  288.           begin
  289.             b[blocksize+1]:=0;
  290.             b[blocksize+2]:=0;
  291.             computecrc (b,blocksize+2,crc);
  292.             b[blocksize+1]:=hi(crc);
  293.             b[blocksize+2]:=lo(crc);
  294.             bksize:=blocksize+2;
  295.           end
  296.         else
  297.           begin
  298.             b[blocksize+1]:=0;
  299.             computecksum (b,blocksize,b[blocksize+1]);
  300.             bksize:=blocksize+1
  301.           end;
  302.       sendchar (k);
  303.       sendchar (chr(n));
  304.       sendchar (chr(255-n));
  305.       for cnt:=1 to bksize do sendchar(chr(b[cnt]))
  306.     end;
  307.  
  308.     Procedure updatestatus;
  309.     begin
  310.       gotoxy (16,3);
  311.       write (usr,curblk,' of ',fsize);
  312.       gotoxy (16,4);
  313.       write (usr,minstr((fsize-curblk)*blocksatatime),' of ',totaltime,' ');
  314.       gotoxy (16,5);
  315.       showerrorstats (curblk,totalerrs,consec)
  316.     end;
  317.  
  318.     Procedure initxfer;
  319.     begin
  320.       starttimer (numminsxfer);
  321.       if ymodem then blocksatatime:=8 else blocksatatime:=1;
  322.       fsize:=(filesize(f)+blocksatatime-1) div blocksatatime;
  323.       totaltime:=minstr(fsize*blocksatatime);
  324.       totalerrs:=0;
  325.       consec:=0;
  326.       firstblock:=true;
  327.       if ymodem
  328.         then
  329.           begin
  330.             curblk:=0;
  331.             buildfirstblock
  332.           end
  333.         else
  334.           begin
  335.             curblk:=1;
  336.             getblockfromfile
  337.           end;
  338.       splitscreen (8);
  339.       top;
  340.       write (usr,'Waiting for NAK')
  341.     end;
  342.  
  343.     Procedure setupscreen;
  344.     begin
  345.       gotoxy (1,1);
  346.       if ymodem then write (usr,'Y') else write (usr,'X');
  347.       write (usr,'MODEM');
  348.       if crcmode then write (usr,'-CRC');
  349.       writeln (usr,' send in progress.  Press Ctrl-X to abort.');
  350.       clreol;
  351.       gotoxy (1,3);
  352.       writeln (usr,'Current block:');
  353.       writeln (usr,'Time left:');
  354.       writeln (usr,'Total errors:');
  355.       writeln (usr,'  Consecutive:');
  356.       write (usr,'Error rate:')
  357.     end;
  358.  
  359.   label abort,done;
  360.   begin
  361.     xymodemsend:=2;
  362.     assign (f,fn);
  363.     reset (f);
  364.     iocode:=ioresult;
  365.     if iocode<>0 then exit;
  366.     initxfer;
  367.     repeat
  368.       k:=getctrlchar;
  369.       if k=can then begin
  370.         if (curblk>(fsize*3/4)) and (curblk>2)
  371.           then xymodemsend:=1; { Cheater! }
  372.         goto abort
  373.       end;
  374.       if firstblock then begin
  375.         if (k=nak) or (k=crcstart) then firstblock:=false;
  376.         crcmode:=k=crcstart;
  377.         setupscreen;
  378.         k:=#0
  379.       end;
  380.       if k=ack then begin
  381.         curblk:=curblk+1;
  382.         if eof(f) then goto done;
  383.         getblockfromfile
  384.       end;
  385.       if k<>nak then consec:=0 else begin
  386.         totalerrs:=totalerrs+1;
  387.         consec:=consec+1
  388.       end;
  389.       sendblock(curblk);
  390.       updatestatus
  391.     until 0=1;
  392.     done:
  393.     sendendoffile;
  394.     xymodemsend:=0;
  395.     abort:
  396.     close (f);
  397.     unsplit;
  398.     stoptimer (numminsxfer)
  399.   end;
  400.  
  401.   {overlay} Function xymodemreceive(ymodem:boolean):integer;
  402.   VAR f:file;
  403.       block:array [1..1026] of byte;
  404.       blkl,blkh,xblkl,nblkl,nblk1:byte;
  405.       curblk:integer;
  406.       ctrl,k,k2:char;
  407.       timeul,consec,totalerrs,blocksize:integer;
  408.       canceled,timeout:boolean;
  409.  
  410.     Procedure cancel;
  411.     begin
  412.       wait (10);
  413.       clearmodemahead;
  414.       sendchar (can);
  415.       wait (10);
  416.       clearmodemahead;
  417.       sendchar (can);
  418.       canceled:=true
  419.     end;
  420.  
  421.     Function writeblock:boolean;
  422.     VAR wb:boolean;
  423.     begin
  424.       blockwrite (f,block,blocksize div 128);
  425.       wb:=ioresult=0;
  426.       writeblock:=wb;
  427.       if not wb then begin
  428.         gotoxy (1,1);
  429.         write (usr,'I/O ERROR ',iocode,' WRITING BLOCK');
  430.         clreol;
  431.         sendchar (can);
  432.         wait (10);
  433.         sendchar (can);
  434.         clearmodemahead
  435.       end
  436.     end;
  437.  
  438.     Procedure updatestatus;
  439.     begin
  440.       curblk:=blkl+(blkh shl 8);
  441.       gotoxy (16,3);
  442.       write (usr,curblk);
  443.       gotoxy (16,4);
  444.       showerrorstats (curblk,totalerrs,consec)
  445.     end;
  446.  
  447.     Function sendctrl:char;
  448.     VAR cnt,consec:integer;
  449.         k:char;
  450.     begin
  451.       cnt:=0;
  452.       consec:=0;
  453.       timeout:=false;
  454.       updatestatus;
  455.       sendctrl:=can;
  456.       repeat
  457.         if keyhit then begin
  458.           k:=bioskey;
  459.           if k=^X then begin
  460.             timeout:=true;
  461.             cancel;
  462.             exit
  463.           end
  464.         end;
  465.         sendctrl:=waitchar (50);
  466.         if not timedout then exit;
  467.         sendchar (ctrl);
  468.         cnt:=0;
  469.         consec:=consec+1
  470.       until (consec=10) or hungupon;
  471.       timeout:=true
  472.     end;
  473.  
  474.     Function getachar:char;
  475.     VAR cnt:integer;
  476.         k:char;
  477.     begin
  478.       getachar:=#0;
  479.       timeout:=timeout or hungupon;
  480.       if timeout then exit;
  481.       timeout:=false;
  482.       if keyhit then begin
  483.         k:=bioskey;
  484.         if k=^X then begin
  485.           getachar:=#0;
  486.           timeout:=true;
  487.           cancel;
  488.           exit
  489.         end
  490.       end;
  491.       getachar:=waitchar (10);
  492.       timeout:=timeout or timedout
  493.     end;
  494.  
  495.     Procedure xfererror (txt:lstr);
  496.     begin
  497.       gotoxy (16,7);
  498.       write (usr,txt,' in block ',curblk);
  499.       clreol
  500.     end;
  501.  
  502.     Procedure initxfer;
  503.     VAR k:char;
  504.     begin
  505.       timeul:=timer;
  506.       timeout:=false;
  507.       consec:=0;
  508.       blkl:=1;
  509.       blkh:=0;
  510.       xblkl:=1;
  511.       curblk:=1;
  512.       totalerrs:=0;
  513.       if crcmode
  514.         then ctrl:=crcstart
  515.         else ctrl:=nak;
  516.       canceled:=false;
  517.       starttimer (numminsxfer);
  518.       splitscreen (8);
  519.       top;
  520.       gotoxy (1,1);
  521.       if ymodem then write (usr,'Y') else write (usr,'X');
  522.       write (usr,'MODEM');
  523.       if crcmode then write (usr,'-CRC');
  524.       write (usr,' receive in progress.  Press Ctrl-X to abort.'^M^J^J,
  525.              'Current block:'^M^J,
  526.              'Total errors:'^M^J,
  527.              '  Consecutive:'^M^J,
  528.              'Error rate:'^M^J,
  529.              'Error type:');
  530.       while numchars>0 do k:=getchar
  531.     end;
  532.  
  533.     Procedure endoffile;
  534.     begin
  535.       xymodemreceive:=0;
  536.       sendchar (ack);
  537.       wait (10);
  538.       sendchar (ack);
  539.       clearmodemahead
  540.     end;
  541.  
  542.     Function block0:boolean;
  543.     VAR b0:boolean;
  544.         cnt:integer;
  545.     begin
  546.       b0:=(nblkl=0) and (nblk1=255) and (blkh=0) and (blkl<>255);
  547.       if b0 then begin
  548.         xfererror ('(Receiving block 0...)');
  549.         for cnt:=1 to blocksize do block[cnt]:=ord(getachar);
  550.         ctrl:=ack;
  551.         sendchar (ack)
  552.       end;
  553.       block0:=b0
  554.     end;
  555.  
  556.     Function blocknumerror:boolean;
  557.     VAR bne:boolean;
  558.     begin
  559.       bne:=(nblkl<>(255-nblk1)) or ((nblkl<>xblkl) and (nblkl<>blkl));
  560.       if bne then xfererror ('Block # '+strr(nblkl)+' not '+strr(255-nblk1)+
  561.                              ' and '+strr(xblkl)+' or '+strr(blkl));
  562.       blocknumerror:=bne
  563.     end;
  564.  
  565.     Function resentnoreason:boolean;
  566.     VAR rnr:boolean;
  567.         cnt:integer;
  568.     begin
  569.       rnr:=(nblkl<>xblkl) and (nblkl=blkl);
  570.       if rnr then begin
  571.         xfererror ('Block re-sent for no reason');
  572.         for cnt:=1 to blocksize do block[cnt]:=ord(getachar);
  573.         ctrl:=ack;
  574.         sendchar (ack)
  575.       end;
  576.       resentnoreason:=rnr
  577.     end;
  578.  
  579.     Procedure getblockfrommodem;
  580.     VAR cnt:integer;
  581.     begin
  582.       for cnt:=1 to blocksize do begin
  583.         block[cnt]:=ord(getachar);
  584.         if timeout then exit
  585.       end
  586.     end;
  587.  
  588.     Function badblock:boolean;
  589.     VAR crc:word;
  590.         cksum,reccksum:byte;
  591.     begin
  592.       badblock:=false;
  593.       if crcmode
  594.         then
  595.           begin
  596.             computecrc(block,blocksize,crc);
  597.             if crc<>0 then begin
  598.               xfererror ('CRC error');
  599.               badblock:=true
  600.             end
  601.           end
  602.         else
  603.           begin
  604.             reccksum:=block[129];
  605.             block[129]:=0;
  606.             computecksum(block,blocksize,cksum);
  607.             if cksum<>reccksum then begin
  608.               xfererror ('Checksum error');
  609.               badblock:=true
  610.             end
  611.           end
  612.     end;
  613.  
  614.   label nakit,abort,done;
  615.   begin
  616.     xymodemreceive:=2;
  617.     assign (f,fn);
  618.     rewrite (f);
  619.     iocode:=ioresult;
  620.     if iocode<>0 then begin
  621.       fileerror ('XYMODEMRECEIVE',fn);
  622.       exit
  623.     end;
  624.     initxfer;
  625.     repeat
  626.       k:=sendctrl;
  627.       ctrl:=nak;
  628.       if timeout or (k=can) then goto abort;
  629.       if k=eot then begin
  630.         endoffile;
  631.         goto done
  632.       end;
  633.       case k of
  634.         soh:blocksize:=128;
  635.         stx:blocksize:=1024
  636.         else begin
  637.           xfererror ('SOH error: '+strr(ord(k)));
  638.           goto nakit
  639.         end
  640.       end;
  641.       if crcmode
  642.         then blocksize:=blocksize+2
  643.         else blocksize:=blocksize+1;
  644.       nblkl:=ord(getachar);
  645.       nblk1:=ord(getachar);
  646.       if timeout then goto nakit;
  647.       if block0 then goto nakit;
  648.       if blocknumerror then goto nakit;
  649.       if resentnoreason then goto nakit;
  650.       if (nblkl=0) and (blkl=255) then blkh:=blkh+1;
  651.       blkl:=nblkl;
  652.       getblockfrommodem;
  653.       if timeout then goto nakit;
  654.       if badblock then goto nakit;
  655.       ctrl:=ack;
  656.       xblkl:=blkl+1;
  657.       sendchar (ack);
  658.       updatestatus;
  659.       if not writeblock then goto abort;
  660.       consec:=0;
  661.       nakit:
  662.       if hungupon then goto abort;
  663.       if timeout then xfererror ('Time out (short block)');
  664.       if ctrl<>ack then begin
  665.         totalerrs:=totalerrs+1;
  666.         consec:=consec+1;
  667.         repeat
  668.           k:=waitchar (10)
  669.         until timedout;
  670.         if consec>=15 then begin
  671.           sendchar (can);
  672.           goto abort
  673.         end;
  674.         sendchar (ctrl)
  675.       end
  676.     until 0=1;
  677.     abort:
  678.     cancel;
  679.     done:
  680.     close (f); consec:=ioresult;
  681.     if canceled then begin
  682.       erase (f); consec:=ioresult
  683.     end;
  684.     timeul:=timer-timeul;
  685.     if timeul<0 then timeul:=timeul+1440;
  686.     settimeleft (timeleft+timeul*2);
  687.     unsplit;
  688.     stoptimer (numminsxfer)
  689.   end;
  690.  
  691. begin
  692.   if send
  693.     then protocolxfer:=xymodemsend(ymodem)
  694.     else protocolxfer:=xymodemreceive(ymodem)
  695. end;
  696.  
  697.  
  698. {$ifdef testprotocol}
  699. {*}
  700. {*}
  701. {*}Procedure termmode;
  702. {*}VAR k:char;
  703. {*}begin
  704. {*}  clrscr;
  705. {*}  writeln ('Termmode- ^D when done, or ^A to abort.');
  706. {*}  setparam (1,1200,false);
  707. {*}  repeat
  708. {*}    if keyhit then begin
  709. {*}      k:=bioskey;
  710. {*}      if k=^A then halt else if k=^D then exit else sendchar (k)
  711. {*}    end;
  712. {*}    while numchars>0 do write (getchar)
  713. {*}  until 0=1
  714. {*}end;
  715. {*}VAR k:char;
  716. {*}    fn:lstr;
  717. {*}    b:integer;
  718. {*}    snd,crcm,ymd:boolean;
  719. {*}begin
  720. {*}  checkbreak:=false;
  721. {*}  termmode;
  722. {*}  write ('Filename: ');
  723. {*}  readln (fn);
  724. {*}  if length(fn)=0 then halt;
  725. {*}  write ('S=Send: ');    k:=bioskey;  snd:=upcase(k)='S'; if k=^C then halt;
  726. {*}  write ('C=Crc: ');     k:=bioskey; crcm:=upcase(k)='C'; if k=^C then halt;
  727. {*}  write ('Y=Ymodem: ');  k:=bioskey;  ymd:=upcase(k)='Y'; if k=^C then halt;
  728. {*}  writeln;
  729. {*}  writeln;
  730. {*}  clrscr;
  731. {*}  b:=protocolxfer (snd,crcm,ymd,fn);
  732. {*}  gotoxy (1,24);
  733. {*}  writeln ('Returned: ',b)
  734. {*}
  735. {*}{$endif}
  736.  
  737. end.
  738.