home *** CD-ROM | disk | FTP | other *** search
/ Jason Aller Floppy Collection / 276.img / FORUM21S.ZIP / PROTOCOL.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-02-13  |  17.8 KB  |  729 lines

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