home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c / ucpupd.pas < prev    next >
Pascal/Delphi Source File  |  2020-01-01  |  44KB  |  1,408 lines

  1. |x|*|f6|*|f5|*|f4|*|f3|*|f2|*|f1|{bootstrap the function keys}|.
  2. jff/Change log:/|nsm$log|nqan|{locate & mark the Change log}|.
  3. cfucp1.1upd[begin,end]|n|f6ucp1.1upd|n|{get specified part}|.
  4. bsmbegin|n2fsbsmend|nqa,|{mark beginning and ending lines of this part}|.
  5. jmend|nf/>>>>/ d|g}|!|*c|f1|f4ramdisk:|f1|n|f5|{save next part to ramdisk:}|.
  6. |f3|f3|f3|{main extraction sequence}|.
  7. |xsmend|njfk/|d|e|f2|{extraction initialization, replaced by filename}|.
  8. {>>>> DIR.FIXES.TEXT}
  9. unit dir_fixes;
  10.  
  11. { Change log:
  12. 25 Jul 90 (RTC): added some error handling code
  13. 18 Jul 90 (RTC): Created to fix limitations of dir.info under SFS
  14. }
  15.    
  16. interface
  17.   
  18.   type
  19.     dTimeRec = packed record
  20.                  min : 0..59;
  21.                  hour : 0..24
  22.                end {dTimeRec};
  23.   
  24.   procedure get_lastblk(dunit : integer; var filename : string; 
  25.                         var bytes : integer);
  26.   
  27.   procedure put_lastblk(dunit : integer; var filename : string; 
  28.                         bytes : integer);
  29.   
  30.   procedure get_filetime(dunit : integer; var filename : string; 
  31.                          var the_time : dTimeRec);
  32.   
  33.   procedure put_filetime(dunit : integer; var filename : string; 
  34.                          the_time : dTimeRec);
  35.  
  36. implementation
  37.  
  38.   uses
  39.     {$U syslibr:kernel.code} kernel (directory,dirrange,dirblk,maxdir);
  40.   
  41.   function get_file(dunit : integer; var filename : string;
  42.                     var dir : directory) : dirrange;
  43.     
  44.     var i,j : dirrange;
  45.     
  46.     begin {get_file}
  47.       unitread(dunit,dir,sizeof(directory),dirblk);
  48.       j := 0 {invalid entry number, in case we don't find it};
  49.       for i := 1 to maxdir do
  50.         if filename = dir[i].dtid
  51.           then j := i;
  52.       get_file := j;
  53.       if j = 0 then
  54.         begin
  55.           writeln;
  56.           writeln(chr(7),'ERROR! File "',filename,
  57.                   '" missing from directory of unit #',dunit);
  58.         end
  59.     end {get_file};
  60.   
  61.   procedure put_file(dunit : integer; var dir : directory);
  62.     
  63.     begin {put_file}
  64.       unitwrite(dunit,dir,sizeof(directory),dirblk);
  65.     end {put_file};
  66.   
  67.   procedure get_lastblk{dunit : integer; var filename : string; 
  68.                         var bytes : integer};
  69.     
  70.     var
  71.       disk_dir : directory;
  72.     
  73.     begin {get_lastblk}
  74.       bytes := disk_dir[get_file(dunit,filename,disk_dir)].dlastbyte
  75.     end {get_lastblk};
  76.   
  77.   procedure put_lastblk{dunit : integer; var filename : string; 
  78.                         bytes : integer};
  79.     
  80.     var
  81.       item : dirrange;
  82.       disk_dir : directory;
  83.     
  84.     begin {put_lastblk}
  85.       item := get_file(dunit,filename,disk_dir);
  86.       if item <> 0 then
  87.         begin
  88.           disk_dir[item].dlastbyte := bytes;
  89.           put_file(dunit,disk_dir)
  90.         end
  91.     end {put_lastblk};
  92.   
  93.   procedure get_filetime{dunit : integer; var filename : string; 
  94.                          var the_time : dTimeRec};
  95.     
  96.     var
  97.       disk_dir : directory;
  98.     
  99.     begin {get_filetime}
  100.       with the_time,disk_dir[get_file(dunit,filename,disk_dir)] do
  101.         begin
  102.           min := dminute; hour := (dhour + 24) mod 25 {pred(dhour)}
  103.         end;
  104.     end {get_filetime};
  105.   
  106.   procedure put_filetime{dunit : integer; var filename : string; 
  107.                          the_time : dTimeRec};
  108.     
  109.     var
  110.       item : dirrange;
  111.       disk_dir : directory;
  112.     
  113.     begin {put_filetime}
  114.       item := get_file(dunit,filename,disk_dir);
  115.       if item <> 0 then
  116.         with the_time,disk_dir[item] do
  117.           begin
  118.             dminute := min; dhour := succ(hour) mod 25;
  119.             put_file(dunit,disk_dir)
  120.           end
  121.     end {put_filetime};
  122.  
  123. end. { dir.fixes }
  124. {>>>> SENDER.TEXT}
  125. {$D AFS-}  { indicates to compile to run without Adv. File Sys.}
  126.  
  127. unit sender;
  128.  
  129. interface
  130.  
  131. {Change log:
  132. 25 Jul 90, V1.1: Fixed invalid time attribute bug   RTC
  133. 18 Jul 90, V1.1: Fixed SFS limitations   RTC
  134. 13 May 89, V1.1: Misc. cleanups to debug messages   RTC
  135. 26 Apr 89, V1.1: minor cleanups   RTC
  136. 16 Apr 89, V1.1: Fixed "garbage in buffer" bug         RTC
  137. 13 Apr 89, V1.1: Added Version message          RTC
  138. 14 Aug 88: Fixed timeout state bug       RTC
  139. 07 Aug 88: Added conditional compilation for AFS/SFS difference    RTC
  140. 31 Jul 88: Added Attributes Packets & cancel xfr request from receiver  RTC
  141. 10 Jul 88: Converted to use screenops unit     RTC
  142. 10 Jul 88: Fixed cleareol problem on filenames      RTC
  143. 02 Jul 88: Fixed sinit 8th-bit prefix negotiation bug     RTC
  144. 30 Jun 88: Added Binary and multiple file transfers    RTC
  145.  
  146. }
  147.  
  148.    procedure sendsw(var send_ok: boolean);
  149.    
  150.    procedure sen_version;
  151.  
  152.  
  153. implementation
  154.  
  155. uses
  156.    screenops,   {RTC, 10 Jul 88}
  157.    {$U kermglob.code} kermglob,
  158.    {$U kermutil.code} kermutil,
  159.    {$U kermpack.code} kermpack,
  160.    {$B AFS+} 
  161.    {$U syslibr:attribute.code} attributes, 
  162.    {$E AFS+} {$B AFS-}
  163.    {$U dir.fixes.code} dir_fixes,
  164.    {$E AFS-}
  165.    {$U syslibr:wild.code} wild,
  166.    {$U syslibr:dir.info.code} dirinfo;
  167.  
  168. const
  169.   my_version = '   Sender Unit V1.1, 25 Jul 90';
  170.  
  171.  
  172. procedure sendsw{(var send_ok: boolean)};
  173.  
  174. var
  175.   do_attr, still_sending, discard, next_is_empty : boolean;
  176.   files_to_send : D_listp;
  177.   io_status: integer;
  178.   heap: ^integer;
  179.   {$B AFS-}
  180.   this_file : D_listp;
  181.   {$E AFS-}
  182.  
  183. procedure openfile;
  184.  
  185. (* resets file of appropriate type *)
  186.   
  187.   var
  188.     dummy : boolean;
  189.  
  190.   begin
  191.     if debug then
  192.         debugwrite(concat('Opening ',xfilename));
  193.     (*$I-*) (* turn off compiler i/o checking temporarily *)
  194.     if f_is_binary
  195.       then
  196.         begin
  197.           reset(b_file,xfilename);
  198.           if io_result = 0 then
  199.             {$B AFS+}
  200.             dummy := get_attribute(b_file,FA_lastvalidbyte,last_blksize);
  201.             {$E AFS+} {$B AFS-}
  202.             get_lastblk(files_to_send^.dunit,xfilename,last_blksize);
  203.             {$E AFS-}
  204.           bufend := 0                   {mark the buffer as empty!}
  205.         end
  206.       else reset(t_file,xfilename);
  207.     (*$I+*) (* turn compiler i/o checking back on *)
  208.     io_status := io_result;
  209.     {$B AFS-}
  210.     this_file := files_to_send;
  211.     {$E AFS-}
  212.   end; (* openfile *)
  213.  
  214. function sinit: char;
  215.  
  216. (* send init packet & receive other side's *)
  217.  
  218. var num, len, i: integer;  (* packet number and length *)
  219.     ch: char;
  220.  
  221.   begin
  222.     if debug then
  223.         debugwrite('sinit');
  224.  
  225.     if numtry > maxtry then
  226.       begin
  227.         sinit := 'a';
  228.         exit(sinit)
  229.       end;
  230.  
  231.     num_try := num_try + 1;
  232.     spar(packet);
  233.  
  234.     clear_buf(inport);
  235.  
  236.     refresh_screen(numtry,n);
  237.  
  238.     spack('S',n mod 64,10,packet);
  239.  
  240.     ch := rpack(len,num,recpkt);
  241.  
  242.     if (ch = 'N') then
  243.       begin
  244.         sinit := 's';
  245.         exit(sinit)
  246.       end (* if 'N' *)
  247.     else if (ch = 'Y') then
  248.       begin
  249.         if ((n mod 64) <> num) then       (* not the right ack *)
  250.           begin
  251.             sinit := currstate;
  252.             exit(sinit)
  253.           end;
  254.         rpar(recpkt,len);
  255.         if (xeol = chr(0)) then   (* if they didn't spec eol *)
  256.             xeol := chr(my_eol);    (* use mine *)
  257.         if (quote = chr(0)) then (* if they didn't spec quote *)
  258.             quote := my_quote;     (* use mine *)
  259.         ctl_set := [chr(0)..chr(31),chr(del),quote];
  260.         if en_qbin then ctl_set := ctl_set + [qbin];
  261.         numtry := 0;
  262.         n := n + 1;              (* increase packet number *)
  263.         sinit := 'f';
  264.         exit(sinit)
  265.       end (* else if 'Y' *)
  266.     else if (ch = 'E') then
  267.       begin
  268.         error(recpkt,len);
  269.         sinit := 'a'
  270.       end (* if 'E' *)
  271.     else if (ch = chr(0)) then
  272.         sinit := currstate
  273.     else if (ch <> 'N') then
  274.         sinit := 'a'
  275.   end; (* sinit *)
  276.  
  277. function sattr: char;
  278.  
  279. (* send attributes packet *)
  280.  
  281. var num, len, pkt_len: integer;
  282.     ch: char;
  283.     got_attr : boolean;
  284.     {$B AFS+} 
  285.     file_date : FA_chron;
  286.     {$E AFS+} {$B AFS-} 
  287.     file_time : dTimeRec;
  288.     {$E AFS-}
  289.     packet : packettype;
  290.  
  291.   begin
  292.     if debug then
  293.         debugwrite('sattr');
  294.  
  295.     if numtry > maxtry then
  296.       begin
  297.         sattr := 'a';
  298.         exit(sattr)
  299.       end;
  300.  
  301.     num_try := num_try + 1;
  302.  
  303.     refresh_screen(numtry,n);
  304.     
  305.     {$B AFS+}
  306.     if f_is_binary
  307.       then got_attr := get_attribute(b_file,FA_revision_date,file_date)
  308.       else got_attr := get_attribute(t_file,FA_revision_date,file_date);
  309.     with file_date,date,time do
  310.     {$E AFS+} {$B AFS-}
  311.     get_filetime(this_file^.dunit,xfilename,file_time);
  312.     with this_file^.D_date,file_time do
  313.     {$E AFS-}
  314.       begin
  315.         packet[0] := '#';                   { creation date attribute }
  316.         
  317.         packet[2] := chr(year div 10 + ord('0'));
  318.         packet[3] := chr(year mod 10 + ord('0'));
  319.         packet[4] := chr(month div 10 + ord('0'));
  320.         packet[5] := chr(month mod 10 + ord('0'));
  321.         packet[6] := chr(day div 10 + ord('0'));
  322.         packet[7] := chr(day mod 10 + ord('0'));
  323.         pkt_len := 8;
  324.         if hour <> 24
  325.           then {valid time}
  326.             begin
  327.               packet[8] := ' ';
  328.               packet[9] := chr(hour div 10 + ord('0'));
  329.               packet[10] := chr(hour mod 10 + ord('0'));
  330.               packet[11] := ':';
  331.               packet[12] := chr(min div 10 + ord('0'));
  332.               packet[13] := chr(min mod 10 + ord('0'));
  333.               packet[1] := tochar(chr(12));       { length }
  334.               pkt_len := pkt_len + 6
  335.             end
  336.           else {invalid time}
  337.             begin
  338.               packet[1] := tochar(chr(6));       { length }
  339.             end
  340.       end;
  341.  
  342.     spack('A',n mod 64,pkt_len,packet);
  343.  
  344.     ch := rpack(len,num,recpkt);
  345.  
  346.     if (ch = 'N') then
  347.       begin
  348.         sattr := 'd';
  349.         exit(sattr)
  350.       end (* if 'N' *)
  351.     else if (ch = 'Y') then
  352.       begin
  353.         if ((n mod 64) <> num) then       (* not the right ack *)
  354.           begin
  355.             sattr := currstate;
  356.             exit(sattr)
  357.           end;
  358.         numtry := 0;
  359.         n := n + 1;              (* increase packet number *)
  360.         do_attr := false;
  361.         discard := (len > 0) and (recpkt[0] = 'N');
  362.         if discard
  363.           then sattr := 'z'
  364.           else sattr := 'd';
  365.         exit(sattr)
  366.       end (* else if 'Y' *)
  367.     else if (ch = 'E') then
  368.       begin
  369.         error(recpkt,len);
  370.         sattr := 'a'
  371.       end (* if 'E' *)
  372.     else if (ch = chr(0)) then
  373.         sattr := currstate
  374.     else if (ch <> 'N') then
  375.         sattr := 'a'
  376.   end; (* sattr *)
  377.  
  378. function sdata: char;
  379.  
  380. (* send file data *)
  381.  
  382. var num, len: integer;
  383.     ch: char;
  384.     packarray: array[boolean] of packettype;
  385.     sizearray: array[boolean] of integer;
  386.     current: boolean;
  387.     b: boolean;
  388.  
  389. function other(b: boolean): boolean;
  390.  
  391. (* complements a boolean which is used as array index *)
  392.  
  393.   begin
  394.     if b then
  395.         other := false
  396.     else
  397.         other := true
  398.   end; (* other *)
  399.  
  400.   begin
  401.     discard := false;
  402.     current := true;
  403.     packarray[current] := packet;
  404.     sizearray[current] := size;
  405.     next_is_empty := true;
  406.     while (currstate = 'd') do
  407.       begin
  408.         if (numtry > maxtry) then             (* if too many tries, give up *)
  409.             currstate := 'a';
  410.  
  411.         b := other(current);
  412.         numtry := numtry + 1;
  413.  
  414.                                           (* send a data packet *)
  415.         spack('D',n mod 64,sizearray[current],packarray[current]);
  416.  
  417.         refresh_screen(numtry,n);
  418.         
  419.         if next_is_empty then             (* set up next packet *)
  420.           begin
  421.             sizearray[b] := bufill(packarray[b]);
  422.             next_is_empty := false
  423.           end;
  424.  
  425.         ch := rpack(len,num,recpkt);      (* receive a packet *)
  426.         if ch = 'N' then                  (* NAK, so just stay in this state *)
  427.             if ((n+1) mod 64 <> num) then (* unless NAK for next packet, which 
  428. *)
  429.                 sdata := currstate
  430.             else                          (* is just like ACK for this packet *
  431. )
  432.               begin
  433.                 if num > 0 then
  434.                     num := (num - 1)      (* in which case, decrement num *)
  435.                 else
  436.                     num := 63;
  437.                 ch := 'Y';                (* and indicate an ACK *)
  438.               end; (* else *)
  439.  
  440.         if (ch = 'Y') then
  441.            begin
  442.              if ((n mod 64) <> num) then (* if wrong ACK *)
  443.                (* stay in same state *)
  444.              else
  445.                begin
  446.                  numtry := 0;
  447.                  n := n + 1;
  448.                  current := b;
  449.                  next_is_empty := true;
  450.                  discard := sizearray[current] = at_badblk;
  451.                  if read_ch(keyport, ch) then {check for user canceling send}
  452.                    begin
  453.                      if ord(ch) in [can_cur,can_all]
  454.                        then discard := true;
  455.                      if ord(ch) = can_all
  456.                        then files_to_send := nil
  457.                    end;
  458.                  if len = 1 then {check for receiver canceling send}
  459.                    begin
  460.                      if recpkt[0] in ['X','Z']
  461.                        then discard := true;
  462.                      if recpkt[0] = 'Z'
  463.                        then files_to_send := nil
  464.                    end;
  465.                  if (sizearray[current] = at_eof) or discard then
  466.                      currstate := 'z'            (* set state to eof *)
  467.                  else
  468.                      currstate := 'd'            (* else stay in data state *)
  469.                end {else}
  470.            end (* if *)
  471.           else if (ch = 'E') then
  472.             begin
  473.               error(recpkt,len);
  474.               currstate := 'a'
  475.             end (* if 'E' *)
  476.           else if (ch = chr(0)) then      (* receive failure, so stay in d *)
  477.           else if (ch <> 'N') then
  478.             currstate := 'a'                  (* on anything else goto abort st
  479. ate *)
  480.       end; (* while *)
  481.     size := sizearray[current];
  482.     packet := packarray[current];
  483.     sdata := currstate
  484.   end; (* sdata *)
  485.  
  486. function sfile: char;
  487.  
  488. (* send file header *)
  489.  
  490. var num, len, i: integer;
  491.     ch: char;
  492.     fn: packettype;
  493.     oldfn: string255;
  494.  
  495. procedure legalize(var fn: string255);
  496.  
  497. (* make sure we send only 1 '.' in filename *)
  498.  
  499. var count, i, j, l: integer;
  500.  
  501.   begin
  502.     if not lit_names then
  503.       begin
  504.         count := 0;
  505.         l := length(fn);
  506.         for i := 1 to l do                                  (* count '.'s in fn
  507.  *)
  508.             if fn[i] = '.' then
  509.                 count := count + 1;
  510.         for i := 1 to count-1 do                            (* remove all but 1
  511.  *)
  512.           begin
  513.             j := 1;
  514.             while (j < l) and (fn[j] <> '.') do
  515.                 j := j + 1;                                 (* by finding it *)
  516.             fn := concat(copy(fn,1,j-1),copy(fn,j+1,l-j));  (* and copying arou
  517. nd it *)
  518.             l := l - 1
  519.           end (* for i *)
  520.       end;
  521.     i := pos(':',fn);
  522.     if i <> 0 then
  523.       fn := copy(fn,i+1,length(fn)-i)         {remove Vol. name}
  524.   end; (* legalize *)
  525.  
  526.   begin
  527.     if debug then
  528.         debugwrite('sfile');
  529.  
  530.     if (numtry > maxtry) then          (* if too many tries, give up *)
  531.       begin
  532.         sfile := 'a';
  533.         exit(sfile)
  534.       end;
  535.     numtry := numtry + 1;
  536.  
  537.     oldfn := xfilename;
  538.     legalize(xfilename);                (* make filename acceptable to remote *
  539. )
  540.     len := length(xfilename);
  541.  
  542.     moveleft(xfilename[1],fn[0],len);   (* move filename into a packettype *)
  543.  
  544.     SC_erase_to_EOL(filepos,fileline);
  545.     write(oldfn,' ==> ',xfilename);
  546.  
  547.     refresh_screen(numtry,n);
  548.  
  549.     spack('F',n mod 64,len,fn);               (* send file header packet *)
  550.  
  551.     if next_is_empty then
  552.       begin
  553.         size := bufill(packet);            (* get first data from file *)
  554.         next_is_empty := false
  555.       end;                             (* while waiting for response *)
  556.  
  557.     ch := rpack(len,num,recpkt);
  558.     if ch = 'N' then                   (* NAK, so just stay in this state *)
  559.         if ((n+1) mod 64 <> num) then  (* unless NAK for next packet, which *)
  560.           begin
  561.             sfile := 'f';
  562.             exit(sfile)                (* is just like ACK for this packet *)
  563.           end
  564.         else
  565.           begin
  566.             if (num > 0) then
  567.                 num := (num - 1)       (* in which case, decrement num *)
  568.             else
  569.                 num := 63;
  570.             ch := 'Y';                 (* and indicate an ACK *)
  571.           end; (* else *)
  572.  
  573.     if (ch = 'Y') then
  574.       begin
  575.         if ((n mod 64) <> num) then  (* if wrong ACK, stay in F state *)
  576.           begin
  577.             sfile := 'f';
  578.             exit(sfile)
  579.           end;
  580.         numtry := 0;
  581.         n := n + 1;
  582.         do_attr := en_attr;
  583.         sfile := 'd';
  584.       end (* if *)
  585.     else if (ch = 'E') then
  586.       begin
  587.         error(recpkt,len);
  588.         sfile := 'a'
  589.       end (* if 'E' *)
  590.     else if (ch = chr(0)) then  {stay in f state}
  591.         sfile := 'f'
  592.     else if (ch <> 'N') then (* don't recognize it *)
  593.         sfile := 'a'
  594.   end; (* sfile *)
  595.  
  596. function seof: char;
  597.  
  598. (* send end of file *)
  599.  
  600. var num, len: integer;
  601.     ch: char;
  602.  
  603.   begin
  604.     if debug then
  605.         debugwrite('seof');
  606.  
  607.     if (numtry > maxtry) then          (* if too many tries, give up *)
  608.       begin
  609.         seof := 'a';
  610.         exit(seof)
  611.       end;
  612.     numtry := numtry + 1;
  613.  
  614.     refresh_screen(numtry,n);
  615.  
  616.     packet[0] := 'D';           {set up in case of discard}
  617.     
  618.     spack('Z',(n mod 64),ord(discard),packet);    (* send end of file packet *)
  619.  
  620.     if debug then
  621.         debugwrite('seof1');
  622.  
  623.     ch := rpack(len,num,recpkt);
  624.     if ch = 'N' then                   (* NAK, so just stay in this state *)
  625.         if ((n+1) mod 64 <> num) then  (* unless NAK for next packet, which *)
  626.           begin
  627.             seof := 'z';
  628.             exit(seof)                 (* is just like ACK for this packet *)
  629.           end
  630.         else
  631.           begin
  632.             if num > 0 then
  633.                 num := (num - 1)       (* in which case, decrement num *)
  634.             else
  635.                 num := 63;
  636.             ch := 'Y';                 (* and indicate an ACK *)
  637.           end; (* else *)
  638.  
  639.     if (ch = 'Y') then
  640.       begin
  641.         if debug then
  642.             debugwrite('seof2');
  643.         if ((n mod 64) <> num) then     (* if wrong ACK, stay in Z state *)
  644.           begin
  645.             seof := 'z';
  646.             exit(seof)
  647.           end;
  648.         numtry := 0;
  649.         n := n + 1;
  650.         if debug then
  651.             debugwrite(concat('Closing ',xfilename));
  652.         if f_is_binary
  653.           then close(b_file)
  654.           else close(t_file);
  655.         while files_to_send <> nil do with files_to_send^ do
  656.           begin
  657.             xfilename := concat(D_volume,':',D_title);
  658.             seof := 'f';
  659.             next_is_empty := true;
  660.             
  661.             openfile;
  662.             files_to_send := D_next_entry;
  663.             if io_status <> 0
  664.               then io_error(io_status)
  665.               else exit(seof)
  666.           end {while};
  667.         seof := 'b'
  668.       end (* if *)
  669.     else if (ch = 'E') then
  670.       begin
  671.         error(recpkt,len);
  672.         seof := 'a'
  673.       end (* if 'E' *)
  674.     else if (ch = chr(0)) then         (* receive failed, so stay in z state *)
  675.         seof := 'z'
  676.     else if (ch <> 'N') then           (* other error, just abort *)
  677.         seof := 'a'
  678.   end; (* seof *)
  679.  
  680. function sbreak: char;
  681.  
  682. var num, len: integer;
  683.     ch: char;
  684.  
  685. (* send break (end of transmission) *)
  686.  
  687.   begin
  688.     if debug then
  689.         debugwrite('sbreak');
  690.  
  691.     if (numtry > maxtry) then          (* if too many tries, give up *)
  692.       begin
  693.         sbreak := 'a';
  694.         exit(sbreak)
  695.       end;
  696.     numtry := numtry + 1;
  697.  
  698.     refresh_screen(numtry,n);
  699.  
  700.     spack('B',(n mod 64),0,packet);    (* send Break Transfer packet *)
  701.  
  702.     ch := rpack(len,num,recpkt);
  703.     if ch = 'N' then                   (* NAK, so just stay in this state *)
  704.         if ((n+1) mod 64 <> num) then  (* unless NAK for next packet, which *)
  705.           begin
  706.             sbreak := 'b';
  707.             exit(sbreak)               (* is just like ACK for this packet *)
  708.           end
  709.         else
  710.           begin
  711.             if num > 0 then
  712.                 num := (num - 1)       (* in which case, decrement num *)
  713.             else
  714.                 num := 63;
  715.             ch := 'Y';                 (* and indicate an ACK *)
  716.           end; (* else *)
  717.  
  718.     if (ch = 'Y') then
  719.       begin
  720.         if ((n mod 64) <> num) then    (* if wrong ACK, stay in B state *)
  721.           begin
  722.             sbreak := 'b';
  723.             exit(sbreak)
  724.           end;
  725.         numtry := 0;
  726.         n := n + 1;
  727.         sbreak := 'c'                  (* else, switch state to complete *)
  728.       end (* if *)
  729.     else if (ch = 'E') then
  730.       begin
  731.         error(recpkt,len);
  732.         sbreak := 'a'
  733.       end (* if 'E' *)
  734.     else if (ch = chr(0)) then         (* receive failed, so stay in b state *)
  735.         sbreak := 'b'
  736.     else if (ch <> 'N') then           (* other error, just abort *)
  737.         sbreak := 'a'
  738.   end; (* sbreak *)
  739.  
  740. (* state table switcher for sending *)
  741.  
  742.   begin (* sendsw *)
  743.     mark(heap);
  744.     send_ok := false;
  745.     still_sending := 
  746.         D_dirlist(xfilename,[D_code..D_svol],files_to_send,false) = D_okay;
  747.     if files_to_send <> nil then with files_to_send^ do
  748.       begin
  749.         xfilename := concat(D_volume,':',D_title);
  750.         next_is_empty := true;
  751.         
  752.         openfile;
  753.         files_to_send := D_next_entry;
  754.         if io_status <> 0 then
  755.           begin
  756.             io_error(io_status);
  757.             still_sending := false
  758.           end
  759.       end;
  760.  
  761.     if still_sending then write_screen('Sending');
  762.     currstate := 's';
  763.     n := 0;       (* set packet # *)
  764.     numtry := 0;
  765.     flush_comm;         {flush any garbage in buffer}
  766.     
  767.     while still_sending do
  768.         if currstate in ['d', 'f', 'z', 's', 'b', 'c', 'a'] then
  769.           case currstate of
  770.               'd': if do_attr
  771.                      then currstate := sattr
  772.                      else currstate := sdata;
  773.               'f': currstate := sfile;
  774.               'z': currstate := seof;
  775.               's': currstate := sinit;
  776.               'b': currstate := sbreak;
  777.               'c': begin
  778.                      send_ok := true;
  779.                      still_sending := false
  780.                    end; (* case c *)
  781.               'a': still_sending := false
  782.             end (* case *)
  783.         else (* state not in legal states *)
  784.           begin
  785.             debugwrite('Unknown State');
  786.             still_sending := false
  787.           end (* else *);
  788.     release(heap)
  789.   end; (* sendsw *)
  790.  
  791. procedure sen_version;
  792.   
  793.   begin
  794.     writeln(my_version)
  795.   end {sen_version};
  796.  
  797. end. { sender }
  798. {>>>> RECEIVER.TEXT}
  799. {$D AFS-}       {indicates for compile to run without Adv. File Sys.}
  800.  
  801. unit receiver;
  802.  
  803. interface
  804.  
  805. {Change log:
  806. 18 Jul 90, V1.1: Fixed SFS limitations   RTC
  807. 18 May 89, V1.1: Added debugdate to reread file dates (fixed date bug[??]) RTC
  808. 13 May 89, V1.1: Misc. cleanup to debug messages   RTC
  809. 30 Apr 89, V1.1: Fixed receiver won't stop on maxtry bug   RTC
  810. 26 Apr 89, V1.1: minor cleanups   RTC
  811. 16 Apr 89, V1.1: Fixed "garbage in buffer" bug       RTC
  812. 16 Apr 89, V1.1: Fixed "short text filename" bug.   RTC
  813. 15 Apr 89, V1.1: Added GET protocol & debug logging of date set result    RTC
  814. 13 Apr 89, V1.1: Added version message          RTC
  815. 17 Aug 88: Fixed garbage after partial last block of bin. file    RTC
  816. 07 Aug 88: Added conditional compilation for AFS/SFS differences   RTC
  817. 31 Jul 88: Added Attribute Packets & user discard requests to sender   RTC
  818. 10 Jul 88: Converted to use screenops unit     RTC
  819. 10 Jul 88: Fixed cleareol problem on filenames     RTC
  820. 02 Jul 88: Added binary file transfer & discard protocol   RTC
  821.  
  822. }
  823.   
  824.   procedure recsw(var rec_ok: boolean; get_from_server : boolean);
  825.   
  826.   procedure rec_version;
  827.  
  828.  
  829. implementation
  830.  
  831. uses
  832.    screenops,   {RTC, 10 Jul 88}
  833.    {$U kermglob.code} kermglob,
  834.    {$U kermutil.code} kermutil,
  835.    {$U kermpack.code} kermpack,
  836.    {$B AFS+} 
  837.    {$U syslibr:attribute.code} attributes; 
  838.    {$E AFS+} {$B AFS-} 
  839.    {$U dir.fixes.code} dir_fixes,
  840.    {$U syslibr:wild.code} wild,
  841.    {$U syslibr:dir.info.code} dirinfo;
  842.    {$E AFS-}
  843.  
  844. const
  845.   my_version = '   Receiver Unit V1.1, 18 Jul 90';
  846.  
  847. {$B AFS-}
  848. procedure debugdate;
  849.   
  850.   var
  851.     heap : ^integer;
  852.     list : D_listp;
  853.     rslt : D_result;
  854.   
  855.   begin {debugdate}
  856.     mark(heap);
  857.     rslt := D_dirlist(xfilename,[Dvol..Ddir],list,false);
  858.     if rslt <> D_okay then debugwrite('Can''t Access File Date');
  859.     if debug then with list^,D_date do
  860.       begin
  861.         debugwrite('');
  862.         write(debf,'File ',D_volume,':',D_title,' Current Date = ',
  863.               month,'/',day,'/',year)
  864.       end;
  865.     release(heap)
  866.   end {debugdate};
  867. {$E AFS-}
  868.  
  869. procedure recsw{(var rec_ok: boolean; get_from_server : boolean)};
  870.  
  871. var
  872.   date_attr : record
  873.                 valid : boolean;
  874.                 value : {$B AFS+} FA_chron {$E AFS+}
  875.                         {$B AFS-}
  876.                         record
  877.                           date : D_daterec;
  878.                           time : D_timerec
  879.                         end;
  880.                         {$E AFS-}
  881.               end;
  882.  
  883. function bufattr(buffer : packettype; len : integer) : integer;
  884.   
  885.   var
  886.     sp_pos,i,j,buffered : integer;
  887.     tempattr : string;
  888.   
  889.   begin {bufattr}
  890.     packet[0] := 'Y'; buffered := 1;    {agree to accept file}
  891.     i := 0; while i < len do
  892.       begin
  893.         if buffer[i] in ['#'] then      {acceptable attribute}
  894.           begin
  895.             tempattr := '';
  896.             for j := 1 to ord(unchar(buffer[succ(i)])) do
  897.               begin
  898.                 tempattr := concat(tempattr,' ');
  899.                 tempattr[length(tempattr)] := buffer[succ(i) + j]
  900.               end;
  901.             case buffer[i] of
  902.               '#' : with date_attr,value,date,time do
  903.                 begin
  904.                   sp_pos := pos(' ',tempattr);
  905.                   if sp_pos = 0 then sp_pos := succ(length(tempattr));
  906.                   year := (ord(tempattr[sp_pos-6]) - ord('0')) * 10
  907.                         + (ord(tempattr[sp_pos-5]) - ord('0'));
  908.                   month := (ord(tempattr[sp_pos-4]) - ord('0')) * 10
  909.                          + (ord(tempattr[sp_pos-3]) - ord('0'));
  910.                   day := (ord(tempattr[sp_pos-2]) - ord('0')) * 10
  911.                        + (ord(tempattr[sp_pos-1]) - ord('0'));
  912.                   if length(tempattr) > sp_pos then
  913.                     begin
  914.                       hour := (ord(tempattr[sp_pos+1]) - ord('0')) * 10
  915.                             + (ord(tempattr[sp_pos+2]) - ord('0'));
  916.                       min := (ord(tempattr[sp_pos+4]) - ord('0')) * 10
  917.                             + (ord(tempattr[sp_pos+5]) - ord('0'))
  918.                     end
  919.                   else          {no time provided}
  920.                     begin
  921.                       hour := 24 {non-valid time}; min := 0
  922.                     end;
  923.                   valid := true
  924.                 end
  925.             end {case}
  926.           end
  927.         else                            {reject attribute}
  928.           begin
  929.             packet[buffered] := buffer[i];
  930.             buffered := succ(buffered)
  931.           end;
  932.         i := succ(succ(i) + ord(unchar(buffer[succ(i)])))
  933.       end;
  934.     bufattr := buffered
  935.   end {bufattr};
  936.  
  937. function rdata: char;
  938.  
  939. (* receive file data *)
  940.  
  941. var dummy, num, len: integer;
  942.     ch: char;
  943.     {$B AFS+}
  944.     did_attr : boolean;
  945.     {$E AFS+} {$B AFS-}
  946.     heap : ^integer;
  947.     this_file : D_listp;
  948.     {$E AFS-}
  949.     i: integer;
  950.  
  951.   begin
  952.  
  953.     repeat
  954.         debugwrite('rdata');
  955.         
  956.         if numtry > maxtry then
  957.           begin
  958.             currstate := 'a';
  959.             exit(rdata)
  960.           end;
  961.         num_try := num_try + 1;
  962.  
  963.         ch := rpack(len,num,recpkt);   (* receive a packet *)
  964.  
  965.         refresh_screen(numtry,n);
  966.  
  967.         if (ch = 'D') then             (* got data packet *)
  968.           begin
  969.             if (num <> (n mod 64)) then (* wrong packet *)
  970.               begin
  971.                 if (oldtry > maxtry) then
  972.                   begin
  973.                     rdata := 'a';      (* too many tries, abort *)
  974.                     exit(rdata)
  975.                   end; (* if *)
  976.  
  977.                 if (num = (pred(n) mod 64)) then (* previous packet again *)
  978.                   begin                (* so re-ACK it *)
  979.                     spack('Y',num,0,packet);
  980.                     numtry := 0;       (* reset try counter *)
  981.                                        (* stay in same state *)
  982.                   end (* if *)
  983.                 else                   (* wrong number *)
  984.                     currstate := 'a'       (* so abort *)
  985.               end (* if *)
  986.             else                       (* right packet *)
  987.               begin
  988.                 bufemp(recpkt,len);  (* write data to file *)
  989.                 if read_ch(keyport, ch) then {check if user wants to can}
  990.                   packet[0] := ctl(ch);
  991.                 spack('Y',(n mod 64),ord(ord(ch) in [can_cur,can_all]),
  992.                       packet); (* ACK packet *)
  993.                 oldtry := numtry;      (* reset try counters *)
  994.                 numtry := 0;
  995.                 n := n + 1             (* bump packet number *)
  996.                                        (* stay in data receive state *)
  997.               end (* else *)
  998.           end (* if 'D' *)
  999.         else if ch = 'A' then           { Attributes }
  1000.           begin
  1001.             if (num <> (n mod 64)) then (* wrong packet *)
  1002.               begin
  1003.                 if (oldtry > maxtry) then
  1004.                   begin
  1005.                     rdata := 'a';      (* too many tries, abort *)
  1006.                     exit(rdata)
  1007.                   end; (* if *)
  1008.  
  1009.                 if (num = (pred(n) mod 64)) then (* previous packet again *)
  1010.                   begin                (* so re-ACK it *)
  1011.                     spack('Y',num,0,packet);
  1012.                     numtry := 0;       (* reset try counter *)
  1013.                                        (* stay in same state *)
  1014.                   end (* if *)
  1015.                 else                   (* wrong number *)
  1016.                     currstate := 'a'       (* so abort *)
  1017.               end (* if *)
  1018.             else                       (* right packet *)
  1019.               begin
  1020.                 spack('Y',(n mod 64),bufattr(recpkt,len),packet); (* ACK packet
  1021.  *)
  1022.                 oldtry := numtry;      (* reset try counters *)
  1023.                 numtry := 0;
  1024.                 n := n + 1             (* bump packet number *)
  1025.                                        (* stay in data receive state *)
  1026.               end (* else *)
  1027.           end {if 'A'}
  1028.         else if (ch = 'F') then        (* file header *)
  1029.           begin
  1030.             if (oldtry > maxtry) then
  1031.               begin
  1032.                 rdata := 'a';          (* too many tries, abort *)
  1033.                 exit(rdata)
  1034.               end; (* if *)
  1035.  
  1036.             if (num = (pred(n) mod 64)) then (* previous packet again *)
  1037.               begin                    (* so re-ACK it *)
  1038.                 spack('Y',num,0,packet);
  1039.                 numtry := 0;           (* reset try counter *)
  1040.                                                (* stay in same state *)
  1041.               end (* if *)
  1042.             else
  1043.                 currstate := 'a'           (* not previous packet, abort *)
  1044.           end (* if 'F' *)
  1045.         else if (ch = 'Z') then        (* end of file *)
  1046.           begin
  1047.             if (num <> (n mod 64)) then(* wrong packet, abort *)
  1048.               begin
  1049.                 rdata := 'a';
  1050.                 exit(rdata)
  1051.               end; (* if *)
  1052.             spack('Y',n mod 64,0,packet); (* ok, ACK it *)
  1053.             if (len = 1) and (recpkt[0] = 'D')
  1054.               then
  1055.                 begin
  1056.                   debugwrite(concat('Discarding ',xfilename));
  1057.                   if f_is_binary               {discard the file}
  1058.                     then close(b_file)
  1059.                     else close(t_file)
  1060.                 end
  1061.               else
  1062.                 begin
  1063.                   debugwrite(concat('Closing ',xfilename));
  1064.                   if f_is_binary               (* close up the file *)
  1065.                     then
  1066.                       begin
  1067.                         if bufpos > 1               {data in last block}
  1068.                           then
  1069.                             begin
  1070.                               for dummy := bufpos to blksize do
  1071.                                 filebuf[dummy] := chr(0);
  1072.                               dummy := blockwrite(b_file,filebuf,1);
  1073.                               {$B AFS+}
  1074.                               dummy := pred(bufpos);
  1075.                               did_attr := 
  1076.                                   put_attribute(b_file,FA_lastvalidbyte,dummy)
  1077.                               {$E AFS+}
  1078.                             end;
  1079.                         {$B AFS+}
  1080.                         with date_attr do if valid then {set date}
  1081.                           did_attr :=
  1082.                               put_attribute(b_file,FA_revisiondate,value);
  1083.                         {$E AFS+}
  1084.                         close(b_file,lock)
  1085.                       end
  1086.                     else
  1087.                       begin
  1088.                         {$B AFS+}
  1089.                         with date_attr do if valid then {set date}
  1090.                           did_attr := 
  1091.                               put_attribute(t_file,FA_creationdate,value);
  1092.                         {$E AFS+}
  1093.                         close(t_file,lock)
  1094.                       end;
  1095.                   {$B AFS-}
  1096.                   mark(heap);
  1097.                   if D_dirlist(xfilename,[D_code,D_text,D_data,D_svol],
  1098.                                this_file,false) <> D_okay
  1099.                     then {we have an error... should never occur}
  1100.                       begin
  1101.                         this_file := nil;
  1102.                         debugwrite('Can''t locate Unit containing File')
  1103.                       end
  1104.                     else if f_is_binary and (bufpos > 1) then
  1105.                       put_lastbyte(this_file^.dunit,xfilename,pred(bufpos));
  1106.                   debugdate;
  1107.                   with date_attr do if valid then {set date,time}
  1108.                     begin
  1109.                       case D_changedate(xfilename,value.date,
  1110.                            [D_code,D_text,D_data,D_svol]) of
  1111.                         D_okay :      debugwrite('Date set OK');
  1112.                         D_notfound :  debugwrite('No such File, Date not set');
  1113.                         D_nameerror : debugwrite('Name error, Date not set');
  1114.                         D_offline :   debugwrite('Volume offline, Date not set'
  1115. );
  1116.                         D_other :     debugwrite('Unknown error, Date not set')
  1117. ;
  1118.                       end {case};
  1119.                       if this_file <> nil
  1120.                         then put_filetime(this_file^.dunit,xfilename,value.time
  1121. )
  1122.                     end;
  1123.                   debugdate;
  1124.                   release(heap);
  1125.                   {$E AFS-}
  1126.                 end;
  1127.             bufpos := 1;                {clean up binary file buffer}
  1128.             n :=  n + 1;               (* bump packet counter *)
  1129.             currstate := 'f';              (* go to complete state *)
  1130.           end (* else if 'Z' *)
  1131.         else if (ch = 'E') then        (* error packet *)
  1132.           begin
  1133.             error(recpkt,len);         (* display error *)
  1134.             currstate := 'a'               (* and abort *)
  1135.           end (* if 'E' *)
  1136.         else if (ch <> chr(0)) then    (* some other packet type, *)
  1137.             currstate := 'a'               (* abort *)
  1138.     until (currstate <> 'd');
  1139.     rdata := currstate
  1140.   end; (* rdata *)
  1141.  
  1142. function rfile: char;
  1143.  
  1144. (* receive file header *)
  1145.  
  1146. var num, len: integer;
  1147.     ch: char;
  1148.     oldfn: string255;
  1149.     i: integer;
  1150.  
  1151. procedure makename(recpkt: packettype; var fn: string255; l: integer);
  1152.  
  1153. function exist(fn: string255): boolean;
  1154.  
  1155. (* returns true if file named fn exists *)
  1156.  
  1157. var f: file;
  1158.   
  1159.   begin
  1160.     (*$I-*) (* turn off i/o checking *)
  1161.     reset(f,fn);
  1162.     exist := (ioresult = 0);
  1163.     (*$I+*)
  1164.   end; (* exist *)
  1165.  
  1166. procedure checkname(var fn: string255);
  1167.  
  1168. (* if file fn exists, makes a new name which doesn't *)
  1169. (* does this by changing letters in file name until it *)
  1170. (* finds some combination which doesn't exitst *)
  1171.  
  1172. var ch: char;
  1173.     i: integer;
  1174.  
  1175.   begin
  1176.     i := 1;
  1177.     while (i <= length(fn)) and exist(fn) do
  1178.       begin
  1179.         ch := succ(fn[i]);    {RTC, 13 May 89}
  1180.         if not (ch in ['A'..'Z']) then ch := 'A';
  1181.         while (ch in ['A'..'Z']) and exist(fn) do
  1182.           begin
  1183.             fn[i] := ch;
  1184.             ch := succ(ch);
  1185.           end; (* while *)
  1186.         i := i + 1
  1187.       end; (* while *)
  1188.     end; (* checkname *)
  1189.  
  1190.   begin (* makename *)
  1191.     fn := copy('               ',1,15);    (* stretch length *)
  1192.     moveleft(recpkt[0],fn[1],l);           (* get filename from packet *)
  1193.     oldfn := copy(fn, 1,l);                (* save fn sent to show user *)
  1194.     fn := copy(fn,1,min(15,l));            (* set length of filename *)
  1195.                                            (* and make sure <= 15 *)
  1196.     uppercase(fn);
  1197.     if not f_is_binary then 
  1198.         if (pos('.TEXT',fn) <> length(fn)-4) or (length(fn) < 5) then
  1199.       begin
  1200.         if length(fn) > 10 then
  1201.             fn := copy(fn,1,10);           (* can only be 15 long in all *)
  1202.         fn := concat(fn,'.TEXT');          (* and we'll add .TEXT *)
  1203.       end; (* if *)
  1204.     if fwarn then                          (* if file warning is on *)
  1205.         checkname(fn);                     (* must check that name unique *)
  1206.   end; (* makename *)
  1207.  
  1208.   begin (* rfile *)
  1209.     debugwrite('rfile');
  1210.  
  1211.     if (numtry > maxtry) then         (* if too many tries, give up *)
  1212.       begin
  1213.         rfile := 'a';
  1214.         exit(rfile)
  1215.       end;
  1216.     numtry := numtry + 1;
  1217.  
  1218.     ch := rpack(len,num,recpkt);      (* receive a packet *)
  1219.  
  1220.     refresh_screen(numtry,n);
  1221.  
  1222.     if ch = 'S' then                  (* send init, maybe our ACK lost *)
  1223.       begin
  1224.         if (oldtry > maxtry) then     (* too many tries, abort *)
  1225.           begin
  1226.             rfile := 'a';
  1227.             exit(rfile)
  1228.           end; (* if *)
  1229.  
  1230.         if num = (pred(n) mod 64) then      (* previous packet mod 64? *)
  1231.           begin                       (* yes, ACK it again *)
  1232.             spar(packet);             (* with our send init params *)
  1233.             spack('Y',num,10,packet);
  1234.             numtry := 0;              (* reset try counter *)
  1235.             rfile := currstate;           (* stay in same state *)
  1236.           end (* if *)
  1237.         else                          (* not previous packet, abort *)
  1238.           rfile := 'a'
  1239.       end (* if 'S' *)
  1240.     else if (ch = 'Z') then           (* end of file *)
  1241.       begin
  1242.         if (oldtry > maxtry) then     (* too many tries, abort *)
  1243.           begin
  1244.             rfile := 'a';
  1245.             exit(rfile)
  1246.           end; (* if *)
  1247.  
  1248.         if num = (pred(n) mod 64) then       (* previous packet mod 64? *)
  1249.           begin                       (* yes, ACK it again *)
  1250.             spack('Y',num,0,packet);
  1251.             numtry := 0;
  1252.             rfile := currstate            (* stay in same state *)
  1253.           end (* if *)
  1254.         else
  1255.             rfile := 'a'              (* no, abort *)
  1256.       end (* else if *)
  1257.     else if (ch = 'F') then           (* file header *)
  1258.       begin                           (* which is what we really want *)
  1259.         if (num <> (n mod 64)) then   (* if wrong packet, abort *)
  1260.           begin
  1261.             rfile := 'a';
  1262.             exit(rfile)
  1263.           end;
  1264.  
  1265.         makename(recpkt,xfilename,len); (* get filename, make unique if filew *
  1266. )
  1267.         SC_erase_to_EOL(filepos,fileline);
  1268.         write(oldfn,' ==> ',xfilename);
  1269.  
  1270.         if not getfil(xfilename) then  (* try to open new file *)
  1271.           begin
  1272.             ioerror(ioresult);        (* if unsuccessful, tell them *)
  1273.             rfile := 'a';             (* and abort *)
  1274.             exit(rfile)
  1275.           end; (* if *)
  1276.  
  1277.         spack('Y',n mod 64,0,packet); (* ACK file header *)
  1278.         
  1279.         {initializations for file attribute data}
  1280.         date_attr.valid := false;
  1281.         {end of initializations for file attribute data}
  1282.         
  1283.         oldtry := numtry;             (* reset try counters *)
  1284.         numtry := 0;
  1285.         n := n + 1;                   (* bump packet number *)
  1286.         rfile := 'd';                 (* switch to data state *)
  1287.       end (* else if *)
  1288.     else if ch = 'B' then             (* break transmission *)
  1289.       begin
  1290.         if (num <> (n mod 64)) then            (* wrong packet, abort *)
  1291.           begin
  1292.             rfile := 'a';
  1293.             exit(rfile)
  1294.           end;
  1295.         spack('Y',n mod 64,0,packet); (* say ok *)
  1296.         rfile := 'c'                  (* go to complete state *)
  1297.       end (* else if *)
  1298.     else if (ch = 'E') then
  1299.       begin
  1300.         error(recpkt,len);
  1301.         rfile := 'a'
  1302.       end
  1303.     else if (ch = chr(0)) then        (* returned false *)
  1304.         rfile := currstate                (* so stay in same state *)
  1305.     else                              (* some weird state, so abort *)
  1306.         rfile := 'a'
  1307.   end; (* rfile *)
  1308.  
  1309. function rinit: char;
  1310.  
  1311. (* receive initialization *)
  1312.  
  1313. var num, len: integer;  (* packet number and length *)
  1314.     ch: char;
  1315.     fn : packettype;
  1316.  
  1317.   begin
  1318.     debugwrite('rinit');
  1319.  
  1320.     if (numtry > maxtry) then         (* if too many tries, give up *)
  1321.       begin
  1322.         rinit := 'a';
  1323.         exit(rinit)
  1324.       end;
  1325.     numtry := numtry + 1;
  1326.     
  1327.     if get_from_server then {ask server for files}
  1328.       begin
  1329.         len := length(xfilename);
  1330.         moveleft(xfilename[1],fn[0],len);
  1331.         spack('R', n mod 64, len, fn)
  1332.       end;
  1333.  
  1334.     ch := rpack(len,num,recpkt); (* receive a packet *)
  1335.     refresh_screen(num_try,n);
  1336.  
  1337.     if (ch = 'S') then           (* send init packet *)
  1338.       begin
  1339.         rpar(recpkt,len);            (* get other side's init data *)
  1340.         spar(packet);            (* fill packet with my init data *)
  1341.         ctl_set := [chr(0)..chr(31),chr(del),quote];
  1342.         if en_qbin then ctl_set := ctl_set + [qbin];
  1343.         spack('Y',n mod 64,10,packet); (* ACK with my params *)
  1344.         get_from_server := false;
  1345.         oldtry := numtry;        (* save old try count *)
  1346.         numtry := 0;             (* start a new counter *)
  1347.         n := n + 1;              (* bump packet number *)
  1348.         rinit := 'f';            (* enter file receive state *)
  1349.       end (* if 'S' *)
  1350.     else if ch = 'Y' then
  1351.       begin
  1352.         rinit := 'r';
  1353.         if n mod 64 = num then {we have the right ACK}
  1354.           begin
  1355.             get_from_server := false;
  1356.             numtry := 0;
  1357.             n := n + 1
  1358.           end
  1359.       end {if 'Y'}
  1360.     else if (ch = 'E') then
  1361.       begin
  1362.         rinit := 'a';
  1363.         error(recpkt,len)
  1364.       end (* if 'E' *)
  1365.     else if (ch = chr(0)) or (ch = 'N')  then
  1366.         rinit := 'r'             (* stay in same state *)
  1367.     else
  1368.         rinit := 'a'             (* abort *)
  1369.   end; (* rinit *)
  1370.  
  1371. (* state table switcher for receiving packets *)
  1372.  
  1373.   begin (* recswok *)
  1374.     rec_ok := false;
  1375.     writescreen('Receiving');
  1376.     currstate := 'r';            (* initial state is receive *)
  1377.     n := 0;                  (* set packet # *)
  1378.     numtry := 0;             (* no tries yet *)
  1379.     flush_comm;         {flush any garbage in buffer}
  1380.  
  1381.     while true do
  1382.         if currstate in ['d', 'f', 'r', 'c', 'a'] then
  1383.           case currstate of
  1384.               'd': currstate := rdata;
  1385.               'f': currstate := rfile;
  1386.               'r': currstate := rinit;
  1387.               'c': begin
  1388.                      rec_ok := true;
  1389.                      exit(recsw)
  1390.                    end; (* case c *)
  1391.               'a': exit(recsw)
  1392.             end (* case *)
  1393.         else (* state not in legal states *)
  1394.           begin
  1395.             debugwrite('Unknown State');
  1396.             exit(recsw)
  1397.           end (* else *)
  1398.   end; (* recsw *)
  1399.  
  1400. procedure rec_version;
  1401.   
  1402.   begin
  1403.     writeln(my_version)
  1404.   end {rec_version};
  1405.  
  1406. end. { receiver }
  1407. {>>>>}
  1408.