home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c / ucpeca.pas < prev    next >
Pascal/Delphi Source File  |  2020-01-01  |  141KB  |  4,441 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. cfucpecan.p[begin,end]|n|f6ucpecan.p|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|f3|f3|f3|f3|f3|f3|f3|f3|f3|f37|n|*|f6|f3|{main extraction sequence}|.
  7. |xsmend|njfk/|d|e|f2|{extraction initialization, replaced by filename}|.
  8. jfd|n|eqa|{remove unwanted filename line}|.
  9. {>>>> KERMIT.TEXT}
  10. program kermit;
  11.  
  12. (* $R-*) (* turn range checking off *)
  13. (* $L+*)
  14.  
  15. USES {$u kermglob.code} kermglob,
  16.      {$U kermutil.code} kermutil,
  17.      {$U parser.code}   parser,
  18.      {$U helper.code}   helper,
  19.      {$U sender.code}   sender,
  20.      {$U receiver.code} receiver,
  21.      {$U client.code}   client;
  22.  
  23. const
  24.   my_version = 'Kermit-UCSD V1.1, 13 May 89';
  25.   
  26. {Change log:
  27.   13 May 89, V1.1: Fixed "lost debug file" bug   RTC
  28.   30 Apr 89, V1.1: Moved set/show & connect procedures to kermutil   RTC
  29.   30 Apr 89, V1.1: Added KERMENUS unit   RTC
  30.   26 Apr 89, V1.1: Fixed "chained TAKE commands" bug     RTC
  31.   19 Apr 89, V1.1: minor cleanups   RTC
  32.   16 Apr 89, V1.1: Added BYE & FINISH commands       RTC
  33.   15 Apr 89, V1.1: Added GET and PUT commands       RTC
  34.   13 Apr 89, V1.1: Began work on new Version   RTC
  35.   17 Aug 88: Misc. cleanup and bug fixes in LOG command      RTC
  36.   14 Aug 88: Added LOG and CLOSE commands         RTC
  37.   31 Jul 88: Modified for variable system_id       RTC
  38.   02 Jul 88: Added Binary transfers & TAKE command     RTC
  39.   29 Jun 88: Fixed Assorted Bugs in "connect" escape functions  RTC
  40.   Modifications by SP, 25 Oct 1983: adapt to IBM Version IV.1
  41.   Delete keyboard and serial buffering: provided by system already.
  42.  
  43.   Additional mods by SP, 18 Mar 1984: make all strings 255 chars long
  44.  
  45.   13 May 84: Incorporate screen control through syscom record entries
  46.              for portability
  47. }
  48.  
  49. var
  50.   taking_commands : boolean;
  51.  
  52. procedure initialize;
  53.  
  54. var ch: char;
  55.  
  56.   begin
  57.     ker_version := my_version;
  58.     writeln(ker_version);
  59.     writeln(
  60. '   This program uses Library Units (c) 1986 Pecan Software Systems, Inc.');
  61.     writeln(
  62. '   This program may be freely distributed for non-commercial purposes.');
  63.     writeln;
  64.     timint := mytime;
  65.     pad := mypad;
  66.     padchar := chr(mypchar);
  67.     xeol := chr(my_eol);
  68.     esc_char := chr(my_esc);
  69.     quote := my_quote;
  70.     ctlset := [chr(0)..chr(31),chr(del),quote];
  71.     half_duplex := false;
  72.     debug := false;
  73.     {$I-}
  74.     rewrite(debf,'CONSOLE:');
  75.     {$I+}
  76.     emulating := false;
  77.     f_is_binary := false;
  78.     lit_names := false;
  79.     fwarn := false;
  80.     spsiz := max_pack;
  81.     rpsiz := max_pack;
  82.     n := 0;
  83.     parity := nopar;
  84.     initvocab;
  85.     fill_parity_array;
  86.     ibm := false;
  87.     xon := chr(17);
  88.     bufpos := 1;
  89.     bufend := 0;
  90.     baud := defaultbaud;
  91.     system_id := 'UNKNOWN';
  92.     if setup_comm then {baud was ok};
  93.     {$I-}
  94.     reset(cmd_file,'*kermitinfo.text');
  95.     taking_commands := io_result = 0;
  96.     if ioresult <> 0 then close(cmd_file)
  97.     {$I+}
  98.   end; (* initialize *)
  99.  
  100.  
  101. procedure closeup;
  102.  
  103.   begin
  104.     close(debf,lock);
  105.     page( output )
  106.   end; (* closeup *)
  107.  
  108.  
  109.   begin (* main kermit program *)
  110.     initialize;
  111.     repeat
  112.         write('Kermit-UCSD> ');
  113.         if taking_commands
  114.           then
  115.             begin
  116.               readln(cmd_file,line);
  117.               writeln(line);
  118.               if eof(cmd_file) then
  119.                 begin
  120.                   close(cmd_file);
  121.                   taking_commands := false
  122.                 end
  123.             end
  124.           else readstr(keyport,line);
  125.         case parse of
  126.             unconfirmed: writeln('Unconfirmed');
  127.             parm_expected: writeln('Parameter expected');
  128.             ambiguous: writeln('Ambiguous');
  129.             unrec: writeln('Unrecognized command');
  130.             fn_expected: writeln('File name expected');
  131.             ch_expected: writeln('Single character expected');
  132.             null: case verb of
  133.                       consym: connect;
  134.                       helpsym: help;
  135.                       logsym:   begin
  136.                                   {$I-}
  137.                                   case adj of
  138.                                     debugsym:
  139.                                       begin
  140.                                         close(debf,lock);
  141.                                         rewrite(debf,xfilename)
  142.                                       end;
  143.                                   end {case adj};
  144.                                   if ioresult <> 0 then
  145.                                     begin
  146.                                       writeln('Unable to open ',xfilename);
  147.                                       case adj of
  148.                                         debugsym:
  149.                                           begin
  150.                                             close(debf);
  151.                                             rewrite(debf,'CONSOLE:')
  152.                                           end;
  153.                                       end {case adj};
  154.                                     end
  155.                                   else {$I+}
  156.                                     case adj of
  157.                                       debugsym: write(debf,
  158.                                           ker_version,' -- Debug log...');
  159.                                     end
  160.                                 end;
  161.                       closesym: begin
  162.                                   {$I-}
  163.                                   case adj of
  164.                                     debugsym: close(debf,lock);
  165.                                   end {case adj};
  166.                                   if ioresult <> 0 then
  167.                                     begin
  168.                                       writeln('Unable to close file');
  169.                                     end;
  170.                                   case adj of
  171.                                     debugsym: rewrite(debf,'CONSOLE:');
  172.                                   end {case adj};
  173.                                   {$I+}
  174.                                 end;
  175.                       takesym : begin
  176.                                   {$I-}
  177.                                   if taking_commands
  178.                                     then close(cmd_file);
  179.                                   reset(cmd_file,xfilename);
  180.                                   taking_commands := io_result = 0;
  181.                                   if ioresult <> 0 then close(cmd_file)
  182.                                   {$I+}
  183.                                 end;
  184.                       getsym, recsym: begin
  185.                           recsw(rec_ok,verb = getsym);
  186.                           gotoxy(0,debugline);
  187.                           write(chr(bell));
  188.                           if rec_ok then
  189.                               writeln('successful receive')
  190.                           else
  191.                               writeln('unsuccessful receive');
  192.                           (*$I-*) (* set i/o checking off *)
  193.                           if f_is_binary
  194.                             then close(b_file)
  195.                             else close(t_file);
  196.                           (*$I+*) (* set i/o checking back on *)
  197.                           gotoxy(0,promptline);
  198.                         end; (* recsym *)
  199.                       putsym, sendsym: begin
  200.                           uppercase(xfilename);
  201.                           sendsw(send_ok);
  202.                           gotoxy(0,debugline);
  203.                           write(chr(bell));
  204.                           if send_ok then
  205.                               writeln('successful send')
  206.                           else
  207.                               writeln('unsuccessful send');
  208.                           (*$I-*) (* set i/o checking off *)
  209.                           if f_is_binary
  210.                             then close(b_file)
  211.                             else close(t_file);
  212.                           (*$I+*) (* set i/o checking back on *)
  213.                           gotoxy(0,promptline);
  214.                         end; (* sendsym *)
  215.                       finsym,byesym: begin
  216.                           case verb of
  217.                             finsym: line := 'F';
  218.                             byesym: line := 'L';
  219.                           end {case};
  220.                           clientsw(send_ok,'G',line);
  221.                           gotoxy(0,debugline);
  222.                           write(chr(bell));
  223.                           if send_ok then
  224.                               writeln('successful transaction')
  225.                           else
  226.                               writeln('unsuccessful transaction');
  227.                           (*$I-*) (* set i/o checking off *)
  228.                           close(t_file);
  229.                           (*$I+*) (* set i/o checking back on *)
  230.                           gotoxy(0,promptline);
  231.                         end; {generic server command}
  232.                       setsym: set_parms;
  233.                       show_sym: show_parms;
  234.                   end; (* case verb *)
  235.         end; (* case parse *)
  236.      until (verb = exitsym) or (verb = quitsym);
  237.      closeup
  238.    end. (* kermit *)
  239. {>>>> SENDER.TEXT}
  240. {$D AFS-}  { indicates to compile to run without Adv. File Sys.}
  241.  
  242. unit sender;
  243.  
  244. interface
  245.  
  246. {Change log:
  247. 13 May 89, V1.1: Misc. cleanups to debug messages   RTC
  248. 26 Apr 89, V1.1: minor cleanups   RTC
  249. 16 Apr 89, V1.1: Fixed "garbage in buffer" bug         RTC
  250. 13 Apr 89, V1.1: Added Version message          RTC
  251. 14 Aug 88: Fixed timeout state bug       RTC
  252. 07 Aug 88: Added conditional compilation for AFS/SFS difference    RTC
  253. 31 Jul 88: Added Attributes Packets & cancel xfr request from receiver  RTC
  254. 10 Jul 88: Converted to use screenops unit     RTC
  255. 10 Jul 88: Fixed cleareol problem on filenames      RTC
  256. 02 Jul 88: Fixed sinit 8th-bit prefix negotiation bug     RTC
  257. 30 Jun 88: Added Binary and multiple file transfers    RTC
  258.  
  259. }
  260.  
  261.    procedure sendsw(var send_ok: boolean);
  262.    
  263.    procedure sen_version;
  264.  
  265.  
  266. implementation
  267.  
  268. uses
  269.    screenops,   {RTC, 10 Jul 88}
  270.    {$U kermglob.code} kermglob,
  271.    {$U kermutil.code} kermutil,
  272.    {$U kermpack.code} kermpack,
  273.    {$B AFS+} {$U syslibr:attribute.code} attributes, {$E AFS+}
  274.    {$U syslibr:wild.code} wild,
  275.    {$U syslibr:dir.info.code} dirinfo;
  276.  
  277. const
  278.   my_version = '   Sender Unit V1.1, 13 May 89';
  279.  
  280.  
  281. procedure sendsw{(var send_ok: boolean)};
  282.  
  283. var
  284.   do_attr, still_sending, discard, next_is_empty : boolean;
  285.   files_to_send : D_listp;
  286.   io_status: integer;
  287.   heap: ^integer;
  288.   {$B AFS-}
  289.   this_file : D_listp;
  290.   {$E AFS-}
  291.  
  292. procedure openfile;
  293.  
  294. (* resets file of appropriate type *)
  295.   
  296.   var
  297.     dummy : boolean;
  298.  
  299.   begin
  300.     if debug then
  301.         debugwrite(concat('Opening ',xfilename));
  302.     (*$I-*) (* turn off compiler i/o checking temporarily *)
  303.     if f_is_binary
  304.       then
  305.         begin
  306.           reset(b_file,xfilename);
  307.           if io_result = 0 then
  308.             {$B AFS+}
  309.             dummy := get_attribute(b_file,FA_lastvalidbyte,last_blksize);
  310.             {$E AFS+} {$B AFS-}
  311.             last_blksize := 512;        {default as we can't determine it}
  312.             {$E AFS-}
  313.           bufend := 0                   {mark the buffer as empty!}
  314.         end
  315.       else reset(t_file,xfilename);
  316.     (*$I+*) (* turn compiler i/o checking back on *)
  317.     io_status := io_result;
  318.     {$B AFS-}
  319.     this_file := files_to_send;
  320.     {$E AFS-}
  321.   end; (* openfile *)
  322.  
  323. function sinit: char;
  324.  
  325. (* send init packet & receive other side's *)
  326.  
  327. var num, len, i: integer;  (* packet number and length *)
  328.     ch: char;
  329.  
  330.   begin
  331.     if debug then
  332.         debugwrite('sinit');
  333.  
  334.     if numtry > maxtry then
  335.       begin
  336.         sinit := 'a';
  337.         exit(sinit)
  338.       end;
  339.  
  340.     num_try := num_try + 1;
  341.     spar(packet);
  342.  
  343.     clear_buf(inport);
  344.  
  345.     refresh_screen(numtry,n);
  346.  
  347.     spack('S',n mod 64,10,packet);
  348.  
  349.     ch := rpack(len,num,recpkt);
  350.  
  351.     if (ch = 'N') then
  352.       begin
  353.         sinit := 's';
  354.         exit(sinit)
  355.       end (* if 'N' *)
  356.     else if (ch = 'Y') then
  357.       begin
  358.         if ((n mod 64) <> num) then       (* not the right ack *)
  359.           begin
  360.             sinit := currstate;
  361.             exit(sinit)
  362.           end;
  363.         rpar(recpkt,len);
  364.         if (xeol = chr(0)) then   (* if they didn't spec eol *)
  365.             xeol := chr(my_eol);    (* use mine *)
  366.         if (quote = chr(0)) then (* if they didn't spec quote *)
  367.             quote := my_quote;     (* use mine *)
  368.         ctl_set := [chr(0)..chr(31),chr(del),quote];
  369.         if en_qbin then ctl_set := ctl_set + [qbin];
  370.         numtry := 0;
  371.         n := n + 1;              (* increase packet number *)
  372.         sinit := 'f';
  373.         exit(sinit)
  374.       end (* else if 'Y' *)
  375.     else if (ch = 'E') then
  376.       begin
  377.         error(recpkt,len);
  378.         sinit := 'a'
  379.       end (* if 'E' *)
  380.     else if (ch = chr(0)) then
  381.         sinit := currstate
  382.     else if (ch <> 'N') then
  383.         sinit := 'a'
  384.   end; (* sinit *)
  385.  
  386. function sattr: char;
  387.  
  388. (* send attributes packet *)
  389.  
  390. var num, len: integer;
  391.     ch: char;
  392.     got_attr : boolean;
  393.     {$B AFS+}
  394.     file_date : FA_chron;
  395.     {$E AFS+}
  396.     packet : packettype;
  397.  
  398.   begin
  399.     if debug then
  400.         debugwrite('sattr');
  401.  
  402.     if numtry > maxtry then
  403.       begin
  404.         sattr := 'a';
  405.         exit(sattr)
  406.       end;
  407.  
  408.     num_try := num_try + 1;
  409.  
  410.     refresh_screen(numtry,n);
  411.     
  412.     packet[0] := '#';                   { creation date attribute }
  413.     {$B AFS+}
  414.     packet[1] := tochar(chr(12));       { length }
  415.     if f_is_binary
  416.       then got_attr := get_attribute(b_file,FA_revision_date,file_date)
  417.       else got_attr := get_attribute(t_file,FA_revision_date,file_date);
  418.     with file_date,date,time do
  419.     {$E AFS+} {$B AFS-}
  420.     packet[1] := tochar(chr(6));        { length }
  421.     with this_file^.D_date do
  422.     {$E AFS-}
  423.       begin
  424.         packet[2] := chr(year div 10 + ord('0'));
  425.         packet[3] := chr(year mod 10 + ord('0'));
  426.         packet[4] := chr(month div 10 + ord('0'));
  427.         packet[5] := chr(month mod 10 + ord('0'));
  428.         packet[6] := chr(day div 10 + ord('0'));
  429.         packet[7] := chr(day mod 10 + ord('0'));
  430.         {$B AFS+}
  431.         packet[8] := ' ';
  432.         packet[9] := chr(hour div 10 + ord('0'));
  433.         packet[10] := chr(hour mod 10 + ord('0'));
  434.         packet[11] := ':';
  435.         packet[12] := chr(min div 10 + ord('0'));
  436.         packet[13] := chr(min mod 10 + ord('0'))
  437.         {$E AFS+}
  438.       end;
  439.  
  440.     spack('A',n mod 64,{$B AFS+}14{$E AFS+} {$B AFS-}8{$E AFS-},packet);
  441.  
  442.     ch := rpack(len,num,recpkt);
  443.  
  444.     if (ch = 'N') then
  445.       begin
  446.         sattr := 'd';
  447.         exit(sattr)
  448.       end (* if 'N' *)
  449.     else if (ch = 'Y') then
  450.       begin
  451.         if ((n mod 64) <> num) then       (* not the right ack *)
  452.           begin
  453.             sattr := currstate;
  454.             exit(sattr)
  455.           end;
  456.         numtry := 0;
  457.         n := n + 1;              (* increase packet number *)
  458.         do_attr := false;
  459.         discard := (len > 0) and (recpkt[0] = 'N');
  460.         if discard
  461.           then sattr := 'z'
  462.           else sattr := 'd';
  463.         exit(sattr)
  464.       end (* else if 'Y' *)
  465.     else if (ch = 'E') then
  466.       begin
  467.         error(recpkt,len);
  468.         sattr := 'a'
  469.       end (* if 'E' *)
  470.     else if (ch = chr(0)) then
  471.         sattr := currstate
  472.     else if (ch <> 'N') then
  473.         sattr := 'a'
  474.   end; (* sattr *)
  475.  
  476. function sdata: char;
  477.  
  478. (* send file data *)
  479.  
  480. var num, len: integer;
  481.     ch: char;
  482.     packarray: array[boolean] of packettype;
  483.     sizearray: array[boolean] of integer;
  484.     current: boolean;
  485.     b: boolean;
  486.  
  487. function other(b: boolean): boolean;
  488.  
  489. (* complements a boolean which is used as array index *)
  490.  
  491.   begin
  492.     if b then
  493.         other := false
  494.     else
  495.         other := true
  496.   end; (* other *)
  497.  
  498.   begin
  499.     discard := false;
  500.     current := true;
  501.     packarray[current] := packet;
  502.     sizearray[current] := size;
  503.     next_is_empty := true;
  504.     while (currstate = 'd') do
  505.       begin
  506.         if (numtry > maxtry) then             (* if too many tries, give up *)
  507.             currstate := 'a';
  508.  
  509.         b := other(current);
  510.         numtry := numtry + 1;
  511.  
  512.                                           (* send a data packet *)
  513.         spack('D',n mod 64,sizearray[current],packarray[current]);
  514.  
  515.         refresh_screen(numtry,n);
  516.         
  517.         if next_is_empty then             (* set up next packet *)
  518.           begin
  519.             sizearray[b] := bufill(packarray[b]);
  520.             next_is_empty := false
  521.           end;
  522.  
  523.         ch := rpack(len,num,recpkt);      (* receive a packet *)
  524.         if ch = 'N' then                  (* NAK, so just stay in this state *)
  525.             if ((n+1) mod 64 <> num) then (* unless NAK for next packet, which *)
  526.                 sdata := currstate
  527.             else                          (* is just like ACK for this packet *)
  528.               begin
  529.                 if num > 0 then
  530.                     num := (num - 1)      (* in which case, decrement num *)
  531.                 else
  532.                     num := 63;
  533.                 ch := 'Y';                (* and indicate an ACK *)
  534.               end; (* else *)
  535.  
  536.         if (ch = 'Y') then
  537.            begin
  538.              if ((n mod 64) <> num) then (* if wrong ACK *)
  539.                (* stay in same state *)
  540.              else
  541.                begin
  542.                  numtry := 0;
  543.                  n := n + 1;
  544.                  current := b;
  545.                  next_is_empty := true;
  546.                  discard := sizearray[current] = at_badblk;
  547.                  if read_ch(keyport, ch) then {check for user canceling send}
  548.                    begin
  549.                      if ord(ch) in [can_cur,can_all]
  550.                        then discard := true;
  551.                      if ord(ch) = can_all
  552.                        then files_to_send := nil
  553.                    end;
  554.                  if len = 1 then {check for receiver canceling send}
  555.                    begin
  556.                      if recpkt[0] in ['X','Z']
  557.                        then discard := true;
  558.                      if recpkt[0] = 'Z'
  559.                        then files_to_send := nil
  560.                    end;
  561.                  if (sizearray[current] = at_eof) or discard then
  562.                      currstate := 'z'            (* set state to eof *)
  563.                  else
  564.                      currstate := 'd'            (* else stay in data state *)
  565.                end {else}
  566.            end (* if *)
  567.           else if (ch = 'E') then
  568.             begin
  569.               error(recpkt,len);
  570.               currstate := 'a'
  571.             end (* if 'E' *)
  572.           else if (ch = chr(0)) then      (* receive failure, so stay in d *)
  573.           else if (ch <> 'N') then
  574.             currstate := 'a'                  (* on anything else goto abort state *)
  575.       end; (* while *)
  576.     size := sizearray[current];
  577.     packet := packarray[current];
  578.     sdata := currstate
  579.   end; (* sdata *)
  580.  
  581. function sfile: char;
  582.  
  583. (* send file header *)
  584.  
  585. var num, len, i: integer;
  586.     ch: char;
  587.     fn: packettype;
  588.     oldfn: string255;
  589.  
  590. procedure legalize(var fn: string255);
  591.  
  592. (* make sure we send only 1 '.' in filename *)
  593.  
  594. var count, i, j, l: integer;
  595.  
  596.   begin
  597.     if not lit_names then
  598.       begin
  599.         count := 0;
  600.         l := length(fn);
  601.         for i := 1 to l do                                  (* count '.'s in fn *)
  602.             if fn[i] = '.' then
  603.                 count := count + 1;
  604.         for i := 1 to count-1 do                            (* remove all but 1 *)
  605.           begin
  606.             j := 1;
  607.             while (j < l) and (fn[j] <> '.') do
  608.                 j := j + 1;                                 (* by finding it *)
  609.             fn := concat(copy(fn,1,j-1),copy(fn,j+1,l-j));  (* and copying around it *)
  610.             l := l - 1
  611.           end (* for i *)
  612.       end;
  613.     i := pos(':',fn);
  614.     if i <> 0 then
  615.       fn := copy(fn,i+1,length(fn)-i)         {remove Vol. name}
  616.   end; (* legalize *)
  617.  
  618.   begin
  619.     if debug then
  620.         debugwrite('sfile');
  621.  
  622.     if (numtry > maxtry) then          (* if too many tries, give up *)
  623.       begin
  624.         sfile := 'a';
  625.         exit(sfile)
  626.       end;
  627.     numtry := numtry + 1;
  628.  
  629.     oldfn := xfilename;
  630.     legalize(xfilename);                (* make filename acceptable to remote *)
  631.     len := length(xfilename);
  632.  
  633.     moveleft(xfilename[1],fn[0],len);   (* move filename into a packettype *)
  634.  
  635.     SC_erase_to_EOL(filepos,fileline);
  636.     write(oldfn,' ==> ',xfilename);
  637.  
  638.     refresh_screen(numtry,n);
  639.  
  640.     spack('F',n mod 64,len,fn);               (* send file header packet *)
  641.  
  642.     if next_is_empty then
  643.       begin
  644.         size := bufill(packet);            (* get first data from file *)
  645.         next_is_empty := false
  646.       end;                             (* while waiting for response *)
  647.  
  648.     ch := rpack(len,num,recpkt);
  649.     if ch = 'N' then                   (* NAK, so just stay in this state *)
  650.         if ((n+1) mod 64 <> num) then  (* unless NAK for next packet, which *)
  651.           begin
  652.             sfile := 'f';
  653.             exit(sfile)                (* is just like ACK for this packet *)
  654.           end
  655.         else
  656.           begin
  657.             if (num > 0) then
  658.                 num := (num - 1)       (* in which case, decrement num *)
  659.             else
  660.                 num := 63;
  661.             ch := 'Y';                 (* and indicate an ACK *)
  662.           end; (* else *)
  663.  
  664.     if (ch = 'Y') then
  665.       begin
  666.         if ((n mod 64) <> num) then  (* if wrong ACK, stay in F state *)
  667.           begin
  668.             sfile := 'f';
  669.             exit(sfile)
  670.           end;
  671.         numtry := 0;
  672.         n := n + 1;
  673.         do_attr := en_attr;
  674.         sfile := 'd';
  675.       end (* if *)
  676.     else if (ch = 'E') then
  677.       begin
  678.         error(recpkt,len);
  679.         sfile := 'a'
  680.       end (* if 'E' *)
  681.     else if (ch = chr(0)) then  {stay in f state}
  682.         sfile := 'f'
  683.     else if (ch <> 'N') then (* don't recognize it *)
  684.         sfile := 'a'
  685.   end; (* sfile *)
  686.  
  687. function seof: char;
  688.  
  689. (* send end of file *)
  690.  
  691. var num, len: integer;
  692.     ch: char;
  693.  
  694.   begin
  695.     if debug then
  696.         debugwrite('seof');
  697.  
  698.     if (numtry > maxtry) then          (* if too many tries, give up *)
  699.       begin
  700.         seof := 'a';
  701.         exit(seof)
  702.       end;
  703.     numtry := numtry + 1;
  704.  
  705.     refresh_screen(numtry,n);
  706.  
  707.     packet[0] := 'D';           {set up in case of discard}
  708.     
  709.     spack('Z',(n mod 64),ord(discard),packet);    (* send end of file packet *)
  710.  
  711.     if debug then
  712.         debugwrite('seof1');
  713.  
  714.     ch := rpack(len,num,recpkt);
  715.     if ch = 'N' then                   (* NAK, so just stay in this state *)
  716.         if ((n+1) mod 64 <> num) then  (* unless NAK for next packet, which *)
  717.           begin
  718.             seof := 'z';
  719.             exit(seof)                 (* is just like ACK for this packet *)
  720.           end
  721.         else
  722.           begin
  723.             if num > 0 then
  724.                 num := (num - 1)       (* in which case, decrement num *)
  725.             else
  726.                 num := 63;
  727.             ch := 'Y';                 (* and indicate an ACK *)
  728.           end; (* else *)
  729.  
  730.     if (ch = 'Y') then
  731.       begin
  732.         if debug then
  733.             debugwrite('seof2');
  734.         if ((n mod 64) <> num) then     (* if wrong ACK, stay in Z state *)
  735.           begin
  736.             seof := 'z';
  737.             exit(seof)
  738.           end;
  739.         numtry := 0;
  740.         n := n + 1;
  741.         if debug then
  742.             debugwrite(concat('Closing ',xfilename));
  743.         if f_is_binary
  744.           then close(b_file)
  745.           else close(t_file);
  746.         while files_to_send <> nil do with files_to_send^ do
  747.           begin
  748.             xfilename := concat(D_volume,':',D_title);
  749.             seof := 'f';
  750.             next_is_empty := true;
  751.             
  752.             openfile;
  753.             files_to_send := D_next_entry;
  754.             if io_status <> 0
  755.               then io_error(io_status)
  756.               else exit(seof)
  757.           end {while};
  758.         seof := 'b'
  759.       end (* if *)
  760.     else if (ch = 'E') then
  761.       begin
  762.         error(recpkt,len);
  763.         seof := 'a'
  764.       end (* if 'E' *)
  765.     else if (ch = chr(0)) then         (* receive failed, so stay in z state *)
  766.         seof := 'z'
  767.     else if (ch <> 'N') then           (* other error, just abort *)
  768.         seof := 'a'
  769.   end; (* seof *)
  770.  
  771. function sbreak: char;
  772.  
  773. var num, len: integer;
  774.     ch: char;
  775.  
  776. (* send break (end of transmission) *)
  777.  
  778.   begin
  779.     if debug then
  780.         debugwrite('sbreak');
  781.  
  782.     if (numtry > maxtry) then          (* if too many tries, give up *)
  783.       begin
  784.         sbreak := 'a';
  785.         exit(sbreak)
  786.       end;
  787.     numtry := numtry + 1;
  788.  
  789.     refresh_screen(numtry,n);
  790.  
  791.     spack('B',(n mod 64),0,packet);    (* send Break Transfer packet *)
  792.  
  793.     ch := rpack(len,num,recpkt);
  794.     if ch = 'N' then                   (* NAK, so just stay in this state *)
  795.         if ((n+1) mod 64 <> num) then  (* unless NAK for next packet, which *)
  796.           begin
  797.             sbreak := 'b';
  798.             exit(sbreak)               (* is just like ACK for this packet *)
  799.           end
  800.         else
  801.           begin
  802.             if num > 0 then
  803.                 num := (num - 1)       (* in which case, decrement num *)
  804.             else
  805.                 num := 63;
  806.             ch := 'Y';                 (* and indicate an ACK *)
  807.           end; (* else *)
  808.  
  809.     if (ch = 'Y') then
  810.       begin
  811.         if ((n mod 64) <> num) then    (* if wrong ACK, stay in B state *)
  812.           begin
  813.             sbreak := 'b';
  814.             exit(sbreak)
  815.           end;
  816.         numtry := 0;
  817.         n := n + 1;
  818.         sbreak := 'c'                  (* else, switch state to complete *)
  819.       end (* if *)
  820.     else if (ch = 'E') then
  821.       begin
  822.         error(recpkt,len);
  823.         sbreak := 'a'
  824.       end (* if 'E' *)
  825.     else if (ch = chr(0)) then         (* receive failed, so stay in b state *)
  826.         sbreak := 'b'
  827.     else if (ch <> 'N') then           (* other error, just abort *)
  828.         sbreak := 'a'
  829.   end; (* sbreak *)
  830.  
  831. (* state table switcher for sending *)
  832.  
  833.   begin (* sendsw *)
  834.     mark(heap);
  835.     send_ok := false;
  836.     still_sending := 
  837.         D_dirlist(xfilename,[D_code..D_svol],files_to_send,false) = D_okay;
  838.     if files_to_send <> nil then with files_to_send^ do
  839.       begin
  840.         xfilename := concat(D_volume,':',D_title);
  841.         next_is_empty := true;
  842.         
  843.         openfile;
  844.         files_to_send := D_next_entry;
  845.         if io_status <> 0 then
  846.           begin
  847.             io_error(io_status);
  848.             still_sending := false
  849.           end
  850.       end;
  851.  
  852.     if still_sending then write_screen('Sending');
  853.     currstate := 's';
  854.     n := 0;       (* set packet # *)
  855.     numtry := 0;
  856.     flush_comm;         {flush any garbage in buffer}
  857.     
  858.     while still_sending do
  859.         if currstate in ['d', 'f', 'z', 's', 'b', 'c', 'a'] then
  860.           case currstate of
  861.               'd': if do_attr
  862.                      then currstate := sattr
  863.                      else currstate := sdata;
  864.               'f': currstate := sfile;
  865.               'z': currstate := seof;
  866.               's': currstate := sinit;
  867.               'b': currstate := sbreak;
  868.               'c': begin
  869.                      send_ok := true;
  870.                      still_sending := false
  871.                    end; (* case c *)
  872.               'a': still_sending := false
  873.             end (* case *)
  874.         else (* state not in legal states *)
  875.           begin
  876.             debugwrite('Unknown State');
  877.             still_sending := false
  878.           end (* else *);
  879.     release(heap)
  880.   end; (* sendsw *)
  881.  
  882. procedure sen_version;
  883.   
  884.   begin
  885.     writeln(my_version)
  886.   end {sen_version};
  887.  
  888. end. { sender }
  889. {>>>> RECEIVER.TEXT}
  890. {$D AFS-}       {indicates for compile to run without Adv. File Sys.}
  891.  
  892. unit receiver;
  893.  
  894. interface
  895.  
  896. {Change log:
  897. 18 May 89, V1.1: Added debugdate to reread file dates (fixed date bug[??]) RTC
  898. 13 May 89, V1.1: Misc. cleanup to debug messages   RTC
  899. 30 Apr 89, V1.1: Fixed receiver won't stop on maxtry bug   RTC
  900. 26 Apr 89, V1.1: minor cleanups   RTC
  901. 16 Apr 89, V1.1: Fixed "garbage in buffer" bug       RTC
  902. 16 Apr 89, V1.1: Fixed "short text filename" bug.   RTC
  903. 15 Apr 89, V1.1: Added GET protocol & debug logging of date set result    RTC
  904. 13 Apr 89, V1.1: Added version message          RTC
  905. 17 Aug 88: Fixed garbage after partial last block of bin. file    RTC
  906. 07 Aug 88: Added conditional compilation for AFS/SFS differences   RTC
  907. 31 Jul 88: Added Attribute Packets & user discard requests to sender   RTC
  908. 10 Jul 88: Converted to use screenops unit     RTC
  909. 10 Jul 88: Fixed cleareol problem on filenames     RTC
  910. 02 Jul 88: Added binary file transfer & discard protocol   RTC
  911.  
  912. }
  913.   
  914.   procedure recsw(var rec_ok: boolean; get_from_server : boolean);
  915.   
  916.   procedure rec_version;
  917.  
  918.  
  919. implementation
  920.  
  921. uses
  922.    screenops,   {RTC, 10 Jul 88}
  923.    {$U kermglob.code} kermglob,
  924.    {$U kermutil.code} kermutil,
  925.    {$U kermpack.code} kermpack,
  926.    {$B AFS+} 
  927.    {$U syslibr:attribute.code} attributes; 
  928.    {$E AFS+} {$B AFS-} 
  929.    {$U syslibr:wild.code} wild,
  930.    {$U syslibr:dir.info.code} dirinfo;
  931.    {$E AFS-}
  932.  
  933. const
  934.   my_version = '   Receiver Unit V1.1, 18 May 89';
  935.  
  936. {$B AFS-}
  937. procedure debugdate;
  938.   
  939.   var
  940.     heap : ^integer;
  941.     list : D_listp;
  942.     rslt : D_result;
  943.   
  944.   begin {debugdate}
  945.     mark(heap);
  946.     rslt := D_dirlist(xfilename,[Dvol..Ddir],list,false);
  947.     if rslt <> D_okay then debugwrite('Can''t Access File Date');
  948.     if debug then with list^,D_date do
  949.       begin
  950.         debugwrite('');
  951.         write(debf,'File ',D_volume,':',D_title,' Current Date = ',
  952.               month,'/',day,'/',year)
  953.       end;
  954.     release(heap)
  955.   end {debugdate};
  956. {$E AFS-}
  957.  
  958. procedure recsw{(var rec_ok: boolean; get_from_server : boolean)};
  959.  
  960. var
  961.   date_attr : record
  962.                 valid : boolean;
  963.                 value : {$B AFS+} FA_chron {$E AFS+}
  964.                         {$B AFS-} D_daterec {$E AFS-}
  965.               end;
  966.  
  967. function bufattr(buffer : packettype; len : integer) : integer;
  968.   
  969.   var
  970.     sp_pos,i,j,buffered : integer;
  971.     tempattr : string;
  972.   
  973.   begin {bufattr}
  974.     packet[0] := 'Y'; buffered := 1;    {agree to accept file}
  975.     i := 0; while i < len do
  976.       begin
  977.         if buffer[i] in ['#'] then      {acceptable attribute}
  978.           begin
  979.             tempattr := '';
  980.             for j := 1 to ord(unchar(buffer[succ(i)])) do
  981.               begin
  982.                 tempattr := concat(tempattr,' ');
  983.                 tempattr[length(tempattr)] := buffer[succ(i) + j]
  984.               end;
  985.             case buffer[i] of
  986.               '#' : with date_attr,value {$B AFS+},date,time{$E AFS+} do
  987.                 begin
  988.                   sp_pos := pos(' ',tempattr);
  989.                   if sp_pos = 0 then sp_pos := succ(length(tempattr));
  990.                   year := (ord(tempattr[sp_pos-6]) - ord('0')) * 10
  991.                         + (ord(tempattr[sp_pos-5]) - ord('0'));
  992.                   month := (ord(tempattr[sp_pos-4]) - ord('0')) * 10
  993.                          + (ord(tempattr[sp_pos-3]) - ord('0'));
  994.                   day := (ord(tempattr[sp_pos-2]) - ord('0')) * 10
  995.                        + (ord(tempattr[sp_pos-1]) - ord('0'));
  996.                   {$B AFS+}
  997.                   if length(tempattr) > sp_pos then
  998.                     begin
  999.                       hour := (ord(tempattr[sp_pos+1]) - ord('0')) * 10
  1000.                             + (ord(tempattr[sp_pos+2]) - ord('0'));
  1001.                       min := (ord(tempattr[sp_pos+4]) - ord('0')) * 10
  1002.                             + (ord(tempattr[sp_pos+5]) - ord('0'))
  1003.                     end
  1004.                   else          {no time provided}
  1005.                     begin
  1006.                       hour := 24 {non-valid time}; min := 0
  1007.                     end;
  1008.                   {$E AFS+}
  1009.                   valid := true
  1010.                 end
  1011.             end {case}
  1012.           end
  1013.         else                            {reject attribute}
  1014.           begin
  1015.             packet[buffered] := buffer[i];
  1016.             buffered := succ(buffered)
  1017.           end;
  1018.         i := succ(succ(i) + ord(unchar(buffer[succ(i)])))
  1019.       end;
  1020.     bufattr := buffered
  1021.   end {bufattr};
  1022.  
  1023. function rdata: char;
  1024.  
  1025. (* receive file data *)
  1026.  
  1027. var dummy, num, len: integer;
  1028.     ch: char;
  1029.     {$B AFS+}
  1030.     did_attr : boolean;
  1031.     {$E AFS+} 
  1032.     i: integer;
  1033.  
  1034.   begin
  1035.  
  1036.     repeat
  1037.         debugwrite('rdata');
  1038.         
  1039.         if numtry > maxtry then
  1040.           begin
  1041.             currstate := 'a';
  1042.             exit(rdata)
  1043.           end;
  1044.         num_try := num_try + 1;
  1045.  
  1046.         ch := rpack(len,num,recpkt);   (* receive a packet *)
  1047.  
  1048.         refresh_screen(numtry,n);
  1049.  
  1050.         if (ch = 'D') then             (* got data packet *)
  1051.           begin
  1052.             if (num <> (n mod 64)) then (* wrong packet *)
  1053.               begin
  1054.                 if (oldtry > maxtry) then
  1055.                   begin
  1056.                     rdata := 'a';      (* too many tries, abort *)
  1057.                     exit(rdata)
  1058.                   end; (* if *)
  1059.  
  1060.                 if (num = (pred(n) mod 64)) then (* previous packet again *)
  1061.                   begin                (* so re-ACK it *)
  1062.                     spack('Y',num,0,packet);
  1063.                     numtry := 0;       (* reset try counter *)
  1064.                                        (* stay in same state *)
  1065.                   end (* if *)
  1066.                 else                   (* wrong number *)
  1067.                     currstate := 'a'       (* so abort *)
  1068.               end (* if *)
  1069.             else                       (* right packet *)
  1070.               begin
  1071.                 bufemp(recpkt,len);  (* write data to file *)
  1072.                 if read_ch(keyport, ch) then {check if user wants to can}
  1073.                   packet[0] := ctl(ch);
  1074.                 spack('Y',(n mod 64),ord(ord(ch) in [can_cur,can_all]),
  1075.                       packet); (* ACK packet *)
  1076.                 oldtry := numtry;      (* reset try counters *)
  1077.                 numtry := 0;
  1078.                 n := n + 1             (* bump packet number *)
  1079.                                        (* stay in data receive state *)
  1080.               end (* else *)
  1081.           end (* if 'D' *)
  1082.         else if ch = 'A' then           { Attributes }
  1083.           begin
  1084.             if (num <> (n mod 64)) then (* wrong packet *)
  1085.               begin
  1086.                 if (oldtry > maxtry) then
  1087.                   begin
  1088.                     rdata := 'a';      (* too many tries, abort *)
  1089.                     exit(rdata)
  1090.                   end; (* if *)
  1091.  
  1092.                 if (num = (pred(n) mod 64)) then (* previous packet again *)
  1093.                   begin                (* so re-ACK it *)
  1094.                     spack('Y',num,0,packet);
  1095.                     numtry := 0;       (* reset try counter *)
  1096.                                        (* stay in same state *)
  1097.                   end (* if *)
  1098.                 else                   (* wrong number *)
  1099.                     currstate := 'a'       (* so abort *)
  1100.               end (* if *)
  1101.             else                       (* right packet *)
  1102.               begin
  1103.                 spack('Y',(n mod 64),bufattr(recpkt,len),packet); (* ACK packet *)
  1104.                 oldtry := numtry;      (* reset try counters *)
  1105.                 numtry := 0;
  1106.                 n := n + 1             (* bump packet number *)
  1107.                                        (* stay in data receive state *)
  1108.               end (* else *)
  1109.           end {if 'A'}
  1110.         else if (ch = 'F') then        (* file header *)
  1111.           begin
  1112.             if (oldtry > maxtry) then
  1113.               begin
  1114.                 rdata := 'a';          (* too many tries, abort *)
  1115.                 exit(rdata)
  1116.               end; (* if *)
  1117.  
  1118.             if (num = (pred(n) mod 64)) then (* previous packet again *)
  1119.               begin                    (* so re-ACK it *)
  1120.                 spack('Y',num,0,packet);
  1121.                 numtry := 0;           (* reset try counter *)
  1122.                                                (* stay in same state *)
  1123.               end (* if *)
  1124.             else
  1125.                 currstate := 'a'           (* not previous packet, abort *)
  1126.           end (* if 'F' *)
  1127.         else if (ch = 'Z') then        (* end of file *)
  1128.           begin
  1129.             if (num <> (n mod 64)) then(* wrong packet, abort *)
  1130.               begin
  1131.                 rdata := 'a';
  1132.                 exit(rdata)
  1133.               end; (* if *)
  1134.             spack('Y',n mod 64,0,packet); (* ok, ACK it *)
  1135.             if (len = 1) and (recpkt[0] = 'D')
  1136.               then
  1137.                 begin
  1138.                   debugwrite(concat('Discarding ',xfilename));
  1139.                   if f_is_binary               {discard the file}
  1140.                     then close(b_file)
  1141.                     else close(t_file)
  1142.                 end
  1143.               else
  1144.                 begin
  1145.                   debugwrite(concat('Closing ',xfilename));
  1146.                   if f_is_binary               (* close up the file *)
  1147.                     then
  1148.                       begin
  1149.                         if bufpos > 1               {data in last block}
  1150.                           then
  1151.                             begin
  1152.                               for dummy := bufpos to blksize do
  1153.                                 filebuf[dummy] := chr(0);
  1154.                               dummy := blockwrite(b_file,filebuf,1);
  1155.                               dummy := pred(bufpos);
  1156.                               {$B AFS+}
  1157.                               did_attr := 
  1158.                                   put_attribute(b_file,FA_lastvalidbyte,dummy)
  1159.                               {$E AFS+}
  1160.                             end;
  1161.                         {$B AFS+}
  1162.                         with date_attr do if valid then {set date}
  1163.                           did_attr :=
  1164.                               put_attribute(b_file,FA_revisiondate,value);
  1165.                         {$E AFS+}
  1166.                         close(b_file,lock)
  1167.                       end
  1168.                     else
  1169.                       begin
  1170.                         {$B AFS+}
  1171.                         with date_attr do if valid then {set date}
  1172.                           did_attr := 
  1173.                               put_attribute(t_file,FA_creationdate,value);
  1174.                         {$E AFS+}
  1175.                         close(t_file,lock)
  1176.                       end;
  1177.                   {$B AFS-}
  1178.                   debugdate;
  1179.                   with date_attr do if valid then {set date}
  1180.                     case D_changedate(xfilename,value,
  1181.                          [D_code,D_text,D_data,D_svol]) of
  1182.                       D_okay :      debugwrite('Date set OK');
  1183.                       D_notfound :  debugwrite('No such File, Date not set');
  1184.                       D_nameerror : debugwrite('Name error, Date not set');
  1185.                       D_offline :   debugwrite('Volume offline, Date not set');
  1186.                       D_other :     debugwrite('Unknown error, Date not set');
  1187.                     end {case};
  1188.                   debugdate;
  1189.                   {$E AFS-}
  1190.                 end;
  1191.             bufpos := 1;                {clean up binary file buffer}
  1192.             n :=  n + 1;               (* bump packet counter *)
  1193.             currstate := 'f';              (* go to complete state *)
  1194.           end (* else if 'Z' *)
  1195.         else if (ch = 'E') then        (* error packet *)
  1196.           begin
  1197.             error(recpkt,len);         (* display error *)
  1198.             currstate := 'a'               (* and abort *)
  1199.           end (* if 'E' *)
  1200.         else if (ch <> chr(0)) then    (* some other packet type, *)
  1201.             currstate := 'a'               (* abort *)
  1202.     until (currstate <> 'd');
  1203.     rdata := currstate
  1204.   end; (* rdata *)
  1205.  
  1206. function rfile: char;
  1207.  
  1208. (* receive file header *)
  1209.  
  1210. var num, len: integer;
  1211.     ch: char;
  1212.     oldfn: string255;
  1213.     i: integer;
  1214.  
  1215. procedure makename(recpkt: packettype; var fn: string255; l: integer);
  1216.  
  1217. function exist(fn: string255): boolean;
  1218.  
  1219. (* returns true if file named fn exists *)
  1220.  
  1221. var f: file;
  1222.   
  1223.   begin
  1224.     (*$I-*) (* turn off i/o checking *)
  1225.     reset(f,fn);
  1226.     exist := (ioresult = 0);
  1227.     (*$I+*)
  1228.   end; (* exist *)
  1229.  
  1230. procedure checkname(var fn: string255);
  1231.  
  1232. (* if file fn exists, makes a new name which doesn't *)
  1233. (* does this by changing letters in file name until it *)
  1234. (* finds some combination which doesn't exitst *)
  1235.  
  1236. var ch: char;
  1237.     i: integer;
  1238.  
  1239.   begin
  1240.     i := 1;
  1241.     while (i <= length(fn)) and exist(fn) do
  1242.       begin
  1243.         ch := succ(fn[i]);    {RTC, 13 May 89}
  1244.         if not (ch in ['A'..'Z']) then ch := 'A';
  1245.         while (ch in ['A'..'Z']) and exist(fn) do
  1246.           begin
  1247.             fn[i] := ch;
  1248.             ch := succ(ch);
  1249.           end; (* while *)
  1250.         i := i + 1
  1251.       end; (* while *)
  1252.     end; (* checkname *)
  1253.  
  1254.   begin (* makename *)
  1255.     fn := copy('               ',1,15);    (* stretch length *)
  1256.     moveleft(recpkt[0],fn[1],l);           (* get filename from packet *)
  1257.     oldfn := copy(fn, 1,l);                (* save fn sent to show user *)
  1258.     fn := copy(fn,1,min(15,l));            (* set length of filename *)
  1259.                                            (* and make sure <= 15 *)
  1260.     uppercase(fn);
  1261.     if not f_is_binary then 
  1262.         if (pos('.TEXT',fn) <> length(fn)-4) or (length(fn) < 5) then
  1263.       begin
  1264.         if length(fn) > 10 then
  1265.             fn := copy(fn,1,10);           (* can only be 15 long in all *)
  1266.         fn := concat(fn,'.TEXT');          (* and we'll add .TEXT *)
  1267.       end; (* if *)
  1268.     if fwarn then                          (* if file warning is on *)
  1269.         checkname(fn);                     (* must check that name unique *)
  1270.   end; (* makename *)
  1271.  
  1272.   begin (* rfile *)
  1273.     debugwrite('rfile');
  1274.  
  1275.     if (numtry > maxtry) then         (* if too many tries, give up *)
  1276.       begin
  1277.         rfile := 'a';
  1278.         exit(rfile)
  1279.       end;
  1280.     numtry := numtry + 1;
  1281.  
  1282.     ch := rpack(len,num,recpkt);      (* receive a packet *)
  1283.  
  1284.     refresh_screen(numtry,n);
  1285.  
  1286.     if ch = 'S' then                  (* send init, maybe our ACK lost *)
  1287.       begin
  1288.         if (oldtry > maxtry) then     (* too many tries, abort *)
  1289.           begin
  1290.             rfile := 'a';
  1291.             exit(rfile)
  1292.           end; (* if *)
  1293.  
  1294.         if num = (pred(n) mod 64) then      (* previous packet mod 64? *)
  1295.           begin                       (* yes, ACK it again *)
  1296.             spar(packet);             (* with our send init params *)
  1297.             spack('Y',num,10,packet);
  1298.             numtry := 0;              (* reset try counter *)
  1299.             rfile := currstate;           (* stay in same state *)
  1300.           end (* if *)
  1301.         else                          (* not previous packet, abort *)
  1302.           rfile := 'a'
  1303.       end (* if 'S' *)
  1304.     else if (ch = 'Z') then           (* end of file *)
  1305.       begin
  1306.         if (oldtry > maxtry) then     (* too many tries, abort *)
  1307.           begin
  1308.             rfile := 'a';
  1309.             exit(rfile)
  1310.           end; (* if *)
  1311.  
  1312.         if num = (pred(n) mod 64) then       (* previous packet mod 64? *)
  1313.           begin                       (* yes, ACK it again *)
  1314.             spack('Y',num,0,packet);
  1315.             numtry := 0;
  1316.             rfile := currstate            (* stay in same state *)
  1317.           end (* if *)
  1318.         else
  1319.             rfile := 'a'              (* no, abort *)
  1320.       end (* else if *)
  1321.     else if (ch = 'F') then           (* file header *)
  1322.       begin                           (* which is what we really want *)
  1323.         if (num <> (n mod 64)) then   (* if wrong packet, abort *)
  1324.           begin
  1325.             rfile := 'a';
  1326.             exit(rfile)
  1327.           end;
  1328.  
  1329.         makename(recpkt,xfilename,len); (* get filename, make unique if filew *)
  1330.         SC_erase_to_EOL(filepos,fileline);
  1331.         write(oldfn,' ==> ',xfilename);
  1332.  
  1333.         if not getfil(xfilename) then  (* try to open new file *)
  1334.           begin
  1335.             ioerror(ioresult);        (* if unsuccessful, tell them *)
  1336.             rfile := 'a';             (* and abort *)
  1337.             exit(rfile)
  1338.           end; (* if *)
  1339.  
  1340.         spack('Y',n mod 64,0,packet); (* ACK file header *)
  1341.         
  1342.         {initializations for file attribute data}
  1343.         date_attr.valid := false;
  1344.         {end of initializations for file attribute data}
  1345.         
  1346.         oldtry := numtry;             (* reset try counters *)
  1347.         numtry := 0;
  1348.         n := n + 1;                   (* bump packet number *)
  1349.         rfile := 'd';                 (* switch to data state *)
  1350.       end (* else if *)
  1351.     else if ch = 'B' then             (* break transmission *)
  1352.       begin
  1353.         if (num <> (n mod 64)) then            (* wrong packet, abort *)
  1354.           begin
  1355.             rfile := 'a';
  1356.             exit(rfile)
  1357.           end;
  1358.         spack('Y',n mod 64,0,packet); (* say ok *)
  1359.         rfile := 'c'                  (* go to complete state *)
  1360.       end (* else if *)
  1361.     else if (ch = 'E') then
  1362.       begin
  1363.         error(recpkt,len);
  1364.         rfile := 'a'
  1365.       end
  1366.     else if (ch = chr(0)) then        (* returned false *)
  1367.         rfile := currstate                (* so stay in same state *)
  1368.     else                              (* some weird state, so abort *)
  1369.         rfile := 'a'
  1370.   end; (* rfile *)
  1371.  
  1372. function rinit: char;
  1373.  
  1374. (* receive initialization *)
  1375.  
  1376. var num, len: integer;  (* packet number and length *)
  1377.     ch: char;
  1378.     fn : packettype;
  1379.  
  1380.   begin
  1381.     debugwrite('rinit');
  1382.  
  1383.     if (numtry > maxtry) then         (* if too many tries, give up *)
  1384.       begin
  1385.         rinit := 'a';
  1386.         exit(rinit)
  1387.       end;
  1388.     numtry := numtry + 1;
  1389.     
  1390.     if get_from_server then {ask server for files}
  1391.       begin
  1392.         len := length(xfilename);
  1393.         moveleft(xfilename[1],fn[0],len);
  1394.         spack('R', n mod 64, len, fn)
  1395.       end;
  1396.  
  1397.     ch := rpack(len,num,recpkt); (* receive a packet *)
  1398.     refresh_screen(num_try,n);
  1399.  
  1400.     if (ch = 'S') then           (* send init packet *)
  1401.       begin
  1402.         rpar(recpkt,len);            (* get other side's init data *)
  1403.         spar(packet);            (* fill packet with my init data *)
  1404.         ctl_set := [chr(0)..chr(31),chr(del),quote];
  1405.         if en_qbin then ctl_set := ctl_set + [qbin];
  1406.         spack('Y',n mod 64,10,packet); (* ACK with my params *)
  1407.         get_from_server := false;
  1408.         oldtry := numtry;        (* save old try count *)
  1409.         numtry := 0;             (* start a new counter *)
  1410.         n := n + 1;              (* bump packet number *)
  1411.         rinit := 'f';            (* enter file receive state *)
  1412.       end (* if 'S' *)
  1413.     else if ch = 'Y' then
  1414.       begin
  1415.         rinit := 'r';
  1416.         if n mod 64 = num then {we have the right ACK}
  1417.           begin
  1418.             get_from_server := false;
  1419.             numtry := 0;
  1420.             n := n + 1
  1421.           end
  1422.       end {if 'Y'}
  1423.     else if (ch = 'E') then
  1424.       begin
  1425.         rinit := 'a';
  1426.         error(recpkt,len)
  1427.       end (* if 'E' *)
  1428.     else if (ch = chr(0)) or (ch = 'N')  then
  1429.         rinit := 'r'             (* stay in same state *)
  1430.     else
  1431.         rinit := 'a'             (* abort *)
  1432.   end; (* rinit *)
  1433.  
  1434. (* state table switcher for receiving packets *)
  1435.  
  1436.   begin (* recswok *)
  1437.     rec_ok := false;
  1438.     writescreen('Receiving');
  1439.     currstate := 'r';            (* initial state is receive *)
  1440.     n := 0;                  (* set packet # *)
  1441.     numtry := 0;             (* no tries yet *)
  1442.     flush_comm;         {flush any garbage in buffer}
  1443.  
  1444.     while true do
  1445.         if currstate in ['d', 'f', 'r', 'c', 'a'] then
  1446.           case currstate of
  1447.               'd': currstate := rdata;
  1448.               'f': currstate := rfile;
  1449.               'r': currstate := rinit;
  1450.               'c': begin
  1451.                      rec_ok := true;
  1452.                      exit(recsw)
  1453.                    end; (* case c *)
  1454.               'a': exit(recsw)
  1455.             end (* case *)
  1456.         else (* state not in legal states *)
  1457.           begin
  1458.             debugwrite('Unknown State');
  1459.             exit(recsw)
  1460.           end (* else *)
  1461.   end; (* recsw *)
  1462.  
  1463. procedure rec_version;
  1464.   
  1465.   begin
  1466.     writeln(my_version)
  1467.   end {rec_version};
  1468.  
  1469. end. { receiver }
  1470. {>>>> CLIENT.TEXT}
  1471.  
  1472. unit client;
  1473.  
  1474. interface
  1475.  
  1476. {Change log:
  1477. 13 May 89, V1.1: Misc. cleanups to debug messages   RTC
  1478. 30 Apr 89, V1.1: Fixed failure to terminate on maxtry bug   RTC
  1479. 26 Apr 89, V1.1: minor cleanups   RTC
  1480. 16 Apr 89, V1.1: Fixed "garbage in buffer" bug        RTC
  1481. 16 Apr 89, V1.1: Adapted CLIENT Unit from RECEIVE Unit         RTC
  1482. }
  1483.   
  1484.   procedure clientsw(var cli_ok: boolean; ptype: char; data: string);
  1485.   
  1486.   procedure cli_version;
  1487.  
  1488.  
  1489. implementation
  1490.  
  1491. uses
  1492.    screenops,   {RTC, 10 Jul 88}
  1493.    {$U kermglob.code} kermglob,
  1494.    {$U kermutil.code} kermutil,
  1495.    {$U kermpack.code} kermpack;
  1496.  
  1497. const
  1498.   my_version = '   Client Unit V1.1, 13 May 89';
  1499.  
  1500. var
  1501.   f_save : boolean;             { save area for f_is_binary }
  1502.  
  1503. procedure clientsw{(var cli_ok: boolean; ptype: char; data: string)};
  1504.  
  1505. function cdata: char;
  1506.  
  1507. (* client text data *)
  1508.  
  1509. var dummy, num, len: integer;
  1510.     ch: char;
  1511.     i: integer;
  1512.  
  1513.   begin
  1514.  
  1515.     repeat
  1516.         debugwrite('cdata');
  1517.         
  1518.         if numtry > maxtry then
  1519.           begin
  1520.             currstate := 'a';
  1521.             exit(cdata)
  1522.           end;
  1523.         num_try := num_try + 1;
  1524.  
  1525.         ch := rpack(len,num,recpkt);   (* receive a packet *)
  1526.  
  1527.         refresh_screen(numtry,n);
  1528.  
  1529.         if (ch = 'D') then             (* got data packet *)
  1530.           begin
  1531.             if (num <> (n mod 64)) then (* wrong packet *)
  1532.               begin
  1533.                 if (oldtry > maxtry) then
  1534.                   begin
  1535.                     cdata := 'a';      (* too many tries, abort *)
  1536.                     exit(cdata)
  1537.                   end; (* if *)
  1538.  
  1539.                 if (num = (pred(n) mod 64)) then (* previous packet again *)
  1540.                   begin                (* so re-ACK it *)
  1541.                     spack('Y',num,0,packet);
  1542.                     numtry := 0;       (* reset try counter *)
  1543.                                        (* stay in same state *)
  1544.                   end (* if *)
  1545.                 else                   (* wrong number *)
  1546.                     currstate := 'a'       (* so abort *)
  1547.               end (* if *)
  1548.             else                       (* right packet *)
  1549.               begin
  1550.                 bufemp(recpkt,len);  (* write data to file *)
  1551.                 if read_ch(keyport, ch) then {check if user wants to can}
  1552.                   packet[0] := ctl(ch);
  1553.                 spack('Y',(n mod 64),ord(ord(ch) in [can_cur,can_all]),
  1554.                       packet); (* ACK packet *)
  1555.                 oldtry := numtry;      (* reset try counters *)
  1556.                 numtry := 0;
  1557.                 n := n + 1             (* bump packet number *)
  1558.                                        (* stay in data receive state *)
  1559.               end (* else *)
  1560.           end (* if 'D' *)
  1561.         else if (ch = 'X') then        (* text header *)
  1562.           begin
  1563.             if (oldtry > maxtry) then
  1564.               begin
  1565.                 cdata := 'a';          (* too many tries, abort *)
  1566.                 exit(cdata)
  1567.               end; (* if *)
  1568.  
  1569.             if (num = (pred(n) mod 64)) then (* previous packet again *)
  1570.               begin                    (* so re-ACK it *)
  1571.                 spack('Y',num,0,packet);
  1572.                 numtry := 0;           (* reset try counter *)
  1573.                                                (* stay in same state *)
  1574.               end (* if *)
  1575.             else
  1576.                 currstate := 'a'           (* not previous packet, abort *)
  1577.           end (* if 'X' *)
  1578.         else if (ch = 'Z') then        (* end of file *)
  1579.           begin
  1580.             if (num <> (n mod 64)) then(* wrong packet, abort *)
  1581.               begin
  1582.                 cdata := 'a';
  1583.                 exit(cdata)
  1584.               end; (* if *)
  1585.             spack('Y',n mod 64,0,packet); (* ok, ACK it *)
  1586.             close(t_file);
  1587.             n :=  n + 1;               (* bump packet counter *)
  1588.             currstate := 'f';              (* go to complete state *)
  1589.           end (* else if 'Z' *)
  1590.         else if (ch = 'E') then        (* error packet *)
  1591.           begin
  1592.             error(recpkt,len);         (* display error *)
  1593.             currstate := 'a'               (* and abort *)
  1594.           end (* if 'E' *)
  1595.         else if (ch <> chr(0)) then    (* some other packet type, *)
  1596.             currstate := 'a'               (* abort *)
  1597.     until (currstate <> 'd');
  1598.     cdata := currstate
  1599.   end; (* cdata *)
  1600.  
  1601. function cfile: char;
  1602.  
  1603. (* client text header *)
  1604.  
  1605. var num, len: integer;
  1606.     ch: char;
  1607.     i: integer;
  1608.  
  1609.   begin (* cfile *)
  1610.     debugwrite('cfile');
  1611.  
  1612.     if (numtry > maxtry) then         (* if too many tries, give up *)
  1613.       begin
  1614.         cfile := 'a';
  1615.         exit(cfile)
  1616.       end;
  1617.     numtry := numtry + 1;
  1618.  
  1619.     ch := rpack(len,num,recpkt);      (* receive a packet *)
  1620.  
  1621.     refresh_screen(numtry,n);
  1622.  
  1623.     if ch = 'S' then                  (* send init, maybe our ACK lost *)
  1624.       begin
  1625.         if (oldtry > maxtry) then     (* too many tries, abort *)
  1626.           begin
  1627.             cfile := 'a';
  1628.             exit(cfile)
  1629.           end; (* if *)
  1630.  
  1631.         if num = (pred(n) mod 64) then      (* previous packet mod 64? *)
  1632.           begin                       (* yes, ACK it again *)
  1633.             spar(packet);             (* with our send init params *)
  1634.             spack('Y',num,10,packet);
  1635.             numtry := 0;              (* reset try counter *)
  1636.             cfile := currstate;           (* stay in same state *)
  1637.           end (* if *)
  1638.         else                          (* not previous packet, abort *)
  1639.           cfile := 'a'
  1640.       end (* if 'S' *)
  1641.     else if (ch = 'Z') then           (* end of file *)
  1642.       begin
  1643.         if (oldtry > maxtry) then     (* too many tries, abort *)
  1644.           begin
  1645.             cfile := 'a';
  1646.             exit(cfile)
  1647.           end; (* if *)
  1648.  
  1649.         if num = (pred(n) mod 64) then       (* previous packet mod 64? *)
  1650.           begin                       (* yes, ACK it again *)
  1651.             spack('Y',num,0,packet);
  1652.             numtry := 0;
  1653.             cfile := currstate            (* stay in same state *)
  1654.           end (* if *)
  1655.         else
  1656.             cfile := 'a'              (* no, abort *)
  1657.       end (* else if *)
  1658.     else if (ch = 'X') then           (* text header *)
  1659.       begin                           (* which is what we really want *)
  1660.         if (num <> (n mod 64)) then   (* if wrong packet, abort *)
  1661.           begin
  1662.             cfile := 'a';
  1663.             exit(cfile)
  1664.           end;
  1665.         
  1666.         if not getfil('console:') then  { try to open console output }
  1667.           begin
  1668.             ioerror(ioresult);          { if unsuccessful, tell them }
  1669.             cfile := 'a';               { and abort }
  1670.             exit(cfile)
  1671.           end;
  1672.  
  1673.         spack('Y',n mod 64,0,packet); (* ACK file header *)
  1674.         
  1675.         oldtry := numtry;             (* reset try counters *)
  1676.         numtry := 0;
  1677.         n := n + 1;                   (* bump packet number *)
  1678.         cfile := 'd';                 (* switch to data state *)
  1679.       end (* else if *)
  1680.     else if ch = 'B' then             (* break transmission *)
  1681.       begin
  1682.         if (num <> (n mod 64)) then            (* wrong packet, abort *)
  1683.           begin
  1684.             cfile := 'a';
  1685.             exit(cfile)
  1686.           end;
  1687.         spack('Y',n mod 64,0,packet); (* say ok *)
  1688.         cfile := 'c'                  (* go to complete state *)
  1689.       end (* else if *)
  1690.     else if (ch = 'E') then
  1691.       begin
  1692.         error(recpkt,len);
  1693.         cfile := 'a'
  1694.       end
  1695.     else if (ch = chr(0)) then        (* returned false *)
  1696.         cfile := currstate                (* so stay in same state *)
  1697.     else                              (* some weird state, so abort *)
  1698.         cfile := 'a'
  1699.   end; (* cfile *)
  1700.  
  1701. function cinit: char;
  1702.  
  1703. (* client initialization *)
  1704.  
  1705. var num, len: integer;  (* packet number and length *)
  1706.     ch: char;
  1707.     cmdpkt : packettype;
  1708.  
  1709.   begin
  1710.     debugwrite('cinit');
  1711.  
  1712.     if (numtry > maxtry) then         (* if too many tries, give up *)
  1713.       begin
  1714.         cinit := 'a';
  1715.         exit(cinit)
  1716.       end;
  1717.     numtry := numtry + 1;
  1718.     len := length(data);
  1719.     moveleft(data[1],cmdpkt[0],len);
  1720.     spack(ptype, n mod 64, len, cmdpkt);
  1721.  
  1722.     ch := rpack(len,num,recpkt); (* receive a packet *)
  1723.     refresh_screen(num_try,n);
  1724.  
  1725.     if (ch = 'S') then           (* send init packet *)
  1726.       begin
  1727.         rpar(recpkt,len);            (* get other side's init data *)
  1728.         spar(packet);            (* fill packet with my init data *)
  1729.         ctl_set := [chr(0)..chr(31),chr(del),quote];
  1730.         if en_qbin then ctl_set := ctl_set + [qbin];
  1731.         spack('Y',n mod 64,10,packet); (* ACK with my params *)
  1732.         oldtry := numtry;        (* save old try count *)
  1733.         numtry := 0;             (* start a new counter *)
  1734.         n := n + 1;              (* bump packet number *)
  1735.         cinit := 'f';            (* enter file receive state *)
  1736.       end (* if 'S' *)
  1737.     else if ch = 'Y' then
  1738.       begin
  1739.         cinit := 'c';
  1740.         if n mod 64 = num then {we have the right ACK}
  1741.           begin
  1742.             numtry := 0;
  1743.             n := n + 1
  1744.           end
  1745.       end {if 'Y'}
  1746.     else if (ch = 'N') then
  1747.       cinit := 'r'
  1748.     else if (ch = 'E') then
  1749.       begin
  1750.         cinit := 'a';
  1751.         error(recpkt,len)
  1752.       end (* if 'E' *)
  1753.     else if (ch = chr(0)) then
  1754.         cinit := 'r'             (* stay in same state *)
  1755.     else
  1756.         cinit := 'a'             (* abort *)
  1757.   end; (* cinit *)
  1758.  
  1759. (* state table switcher for receiving packets *)
  1760.  
  1761.   begin (* clientsw *)
  1762.     cli_ok := false;
  1763.     writescreen('Talking to Server');
  1764.     f_save := f_is_binary; {save for later restore}
  1765.     f_is_binary := false;  {client ONLY recieves text}
  1766.     currstate := 'r';            (* initial state is receive *)
  1767.     n := 0;                  (* set packet # *)
  1768.     numtry := 0;             (* no tries yet *)
  1769.     flush_comm;         {flush any garbage in buffer}
  1770.  
  1771.     while true do
  1772.         if currstate in ['d', 'f', 'r', 'c', 'a'] then
  1773.           case currstate of
  1774.               'd': currstate := cdata;
  1775.               'f': currstate := cfile;
  1776.               'r': currstate := cinit;
  1777.               'c': begin
  1778.                      f_is_binary := f_save;
  1779.                      cli_ok := true;
  1780.                      exit(clientsw)
  1781.                    end; (* case c *)
  1782.               'a': begin
  1783.                      f_is_binary := f_save;
  1784.                      exit(clientsw)
  1785.                    end (* case a *)
  1786.             end (* case *)
  1787.         else (* state not in legal states *)
  1788.           begin
  1789.             debugwrite('Unknown State');
  1790.             f_is_binary := f_save;
  1791.             exit(clientsw)
  1792.           end (* else *)
  1793.   end; (* clientsw *)
  1794.  
  1795. procedure cli_version;
  1796.   
  1797.   begin
  1798.     writeln(my_version)
  1799.   end {cli_version};
  1800.  
  1801. end. { client }
  1802. {>>>> HELPER.TEXT}
  1803. unit helper;
  1804.  
  1805. interface
  1806.  
  1807. {Change log:
  1808. 13 May 89, V1.1: Added SET INTERFACE, COMMENT, and "client" helps   RTC
  1809. 26 Apr 89, V1.1: minor cleanups   RTC
  1810. 13 Apr 89, V1.1: Added Version message         RTC
  1811. 14 Aug 88: Added command helps for SET SYSTEM command      RTC
  1812. 14 Aug 88: Added LOG and CLOSE help commands         RTC
  1813. 31 Jul 88: Minor cleanups of help messages      RTC
  1814. 30 Jun 88: Added -NAMES, -TYPE, and TAKE command helps   RTC
  1815.  
  1816. }
  1817.  
  1818.    procedure help;
  1819.    
  1820.    procedure hlp_version;
  1821.    
  1822.  
  1823. implementation
  1824.  
  1825. uses {$U kermglob.code} kermglob;
  1826.  
  1827. const
  1828.   my_version = '   Helper Unit V1.1, 13 May 89';
  1829.  
  1830. procedure keypress;
  1831.  
  1832. var ch: char;
  1833.  
  1834.   begin
  1835.     write('---------------Press any key to continue---------------');
  1836.     read( keyboard, ch );
  1837.     page(output); {SP}
  1838.   end; (* keypress *)
  1839.  
  1840. procedure help1;
  1841.  
  1842.   var ch: char;
  1843.  
  1844.   begin { help1 }
  1845.     if (noun = nullsym) then begin
  1846.       writeln('KERMIT is a family of  programs that do reliable file transfer');
  1847.       writeln('between computers over TTY lines.',
  1848.               '  KERMIT can also be used to make the ');
  1849.       writeln('microcomputer behave as a terminal',
  1850.               ' for a mainframe.  These are the ');
  1851.       writeln('commands for the UCSD p-System version, KERMIT-UCSD:');
  1852.       writeln
  1853.     end; (* if *)
  1854.  
  1855.     if (noun = nullsym) or (noun = consym) then begin
  1856.       writeln('  CONNECT     To make a "virtual terminal" connection to a remote');
  1857.       writeln('':14, 'system.');
  1858.       writeln;
  1859.       writeln('':14, 'To break the connection and "escape" back to the micro,');
  1860.       writeln('':14, 'type the escape sequence (CTRL-] C, that is Control ');
  1861.       writeln('':14, 'rightbracket followed immediately by the letter C.)');
  1862.       writeln;
  1863.     end; (* if *)
  1864.  
  1865.     if (noun = nullsym) or (noun = exitsym) then begin
  1866.       writeln('  EXIT        To return back to main command level of the p-system.');
  1867.     end; (* if *)
  1868.  
  1869.     if (noun = nullsym) or (noun = quitsym) then begin
  1870.       writeln('  QUIT        Same as EXIT.');
  1871.       writeln;
  1872.     end; (* if *)
  1873.  
  1874.     if (noun = nullsym) or (noun = helpsym) then begin
  1875.       writeln('  HELP        To get a list of KERMIT commands.');
  1876.       writeln;
  1877.     end; (* if *)
  1878.  
  1879.     if (noun = nullsym) or (noun = recsym) then begin
  1880.       writeln('  RECEIVE     To accept a file from the remote system.');
  1881.     end; (* if *)
  1882.     
  1883.     if (noun = nullsym) or (noun = sendsym) then begin
  1884.       writeln('  SEND        To send a file or group of files to the remote system.');
  1885.     end; (* if *)
  1886.  
  1887.     if (noun = nullsym) or (noun = getsym) then begin
  1888.       writeln('  GET         To request a file from a remote Kermit in SERVER mode.');
  1889.     end; (* if *)
  1890.  
  1891.     if (noun = nullsym) or (noun = putsym) then begin
  1892.       writeln('  PUT         To send a file to a remote Kermit in SERVER mode.');
  1893.       writeln;
  1894.     end; (* if *)
  1895.  
  1896.     if (noun = nullsym) or (noun = byesym) then begin
  1897.       writeln('  BYE         Shutdown and logout a remote Kermit in SERVER mode.');
  1898.     end; (* if *)
  1899.  
  1900.     if (noun = nullsym) or (noun = finsym) then begin
  1901.       writeln('  FINISH      Shutdown a remote Kermit in SERVER mode.');
  1902.     end; (* if *)
  1903.  
  1904.     if (noun = nullsym) then
  1905.         keypress;
  1906.   end; (* help1 *)
  1907.  
  1908. procedure help2;
  1909.  
  1910. var ch: char;
  1911.  
  1912.   begin { help2 }
  1913.     if (noun = nullsym) or (noun = setsym) then begin
  1914.       writeln('  SET         To establish system-dependent parameters.  The ');
  1915.       writeln('':14, 'SET options are as follows: ');
  1916.       writeln;
  1917.       if (adj = nullsym) or (adj = debugsym) then begin
  1918.         writeln('':14, 'DEBUG            To set debug mode ON or OFF ');
  1919.         writeln('':31, '(default is OFF).');
  1920.         writeln;
  1921.       end; (* if *)
  1922.       if (adj = nullsym) or (adj = escsym) then begin
  1923.         writeln('':14, 'ESCAPE           To change the escape sequence that ');
  1924.         writeln('':31, 'lets you return to the PC Kermit from');
  1925.         writeln('':31, 'the remote host.  The default is CTRL-] c.');
  1926.         writeln;
  1927.       end; (* if *)
  1928.       if (adj = nullsym) or (adj = filenamsym) then begin
  1929.         writeln('':14, 'FILE-NAMES       LITERAL/CONVERTED, Default is CONVERTED, ');
  1930.         writeln('':31, 'In this Kermit LITERAL Names have');
  1931.         writeln('':31, 'Volume name Stripped, while CONVERTED');
  1932.         writeln('':31, 'Names also have all but the final');
  1933.         writeln('':31, '''.'' removed.');
  1934.         writeln;
  1935.       end; (* if *)
  1936.       if (adj = nullsym) or (adj = filetypesym) then begin
  1937.         writeln('':14, 'FILE-TYPE        BINARY/TEXT Default is TEXT.');
  1938.         writeln;
  1939.       end; (* if *)
  1940.       if (adj = nullsym) or (adj = filewarnsym) then begin
  1941.         writeln('':14, 'FILE-WARNING     ON/OFF, default is OFF.  If ON, ');
  1942.         writeln('':31, 'Kermit will warn you and rename an incoming ');
  1943.         writeln('':31, 'file so as not to write over a file that ');
  1944.         writeln('':31, 'currently exists with the same name');
  1945.         writeln;
  1946.       end; (* if *)
  1947.       if (adj = nullsym) then
  1948.         keypress;
  1949.     end; (* if *)
  1950.   end; (* help2 *)
  1951.  
  1952. procedure help3;
  1953.  
  1954.   begin
  1955.     if (noun = nullsym) or (noun = setsym) then begin
  1956.       if (adj = nullsym) or (adj = baudsym) then begin
  1957.         writeln('':14, 'BAUD             To set the serial baud rate.' );
  1958.         writeln('':31, 'Choices are dependant on your Hardware.' );
  1959.         writeln('':31, 'The default is 1200.');
  1960.         writeln;
  1961.       end; (* if *)
  1962.       if (adj = nullsym) or (adj = ibmsym) then begin
  1963.         writeln('':14, 'IBM              ON/OFF, default is OFF.  This flag ');
  1964.         writeln('':31, 'should be ON only when transfering files');
  1965.         writeln('':31, 'between the micro and an IBM VM/CMS');
  1966.         writeln('':31, 'system.  It also causes the parity to');
  1967.         writeln('':31, 'be set appropriately (mark) and activates');
  1968.         writeln('':31, 'local echoing');
  1969.         writeln;
  1970.       end; (* if *)
  1971.       if (adj = nullsym) or (adj = intsym) then begin
  1972.         writeln('':14, 'INTERFACE        KERMIT/UCSD, default is KERMIT.');
  1973.         writeln('':31, 'Permits selection of prefered User Interface:');
  1974.         writeln('':31, 'KERMIT command line or UCSD menus.');
  1975.         writeln;
  1976.       end; (* if *)
  1977.  
  1978.       if (adj = nullsym) or (adj = localsym) then begin
  1979.         writeln('':14, 'LOCAL-ECHO       ON/OFF, default is OFF.  This sets the');
  1980.         writeln('':31, 'duplex.  It should be ON when using ');
  1981.         writeln('':31, 'the IBM and OFF for the DEC-20.');
  1982.         writeln;
  1983.       end; (* if *)
  1984.  
  1985.       if (adj = nullsym) or (adj = emulatesym) then begin
  1986.         writeln('':14, 'EMULATE          ON/OFF, default is OFF.  This sets the');
  1987.         writeln('':31, 'DataMedia 1520A terminal emulation on or off.');
  1988.         writeln;
  1989.       end; (* if *)
  1990.       if (adj = nullsym) then
  1991.         keypress;
  1992.     end; (* if *)
  1993.   end; (* help3 *)
  1994.  
  1995. procedure help4;
  1996.  
  1997.   begin
  1998.     if (noun = setsym) or (noun = nullsym) then begin
  1999.       if (adj = nullsym) or (adj = systemsym) then begin
  2000.         writeln('':14, 'SYSTEM-ID        Specify the System-ID for your REMUNIT');
  2001.         writeln('':31, 'if your REMUNIT needs it specified.');
  2002.         writeln('':31, 'Called "model" in the REMUNIT specs.');
  2003.         writeln('':31, 'Default System-ID is UNKNOWN');
  2004.         writeln;
  2005.       end; (* if *)
  2006.  
  2007.       if (adj = nullsym) or (adj = paritysym) then begin
  2008.         writeln('':14, 'PARITY           EVEN, ODD, MARK, SPACE, or NONE.');
  2009.         writeln('':31, 'NONE is the default but if the IBM ');
  2010.         writeln('':31, 'flag is set, parity is set to MARK.  ');
  2011.         writeln('':31, 'This flag selects the parity for ');
  2012.         writeln('':31, 'outgoing and incoming characters during');
  2013.         writeln('':31, 'CONNECT and file transfer to match the');
  2014.         writeln('':31, 'requirements of the host.');
  2015.         writeln;
  2016.       end; (* if *)
  2017.     end; (* if *)
  2018.     if (noun = nullsym) or (noun = showsym) then begin
  2019.       writeln('  SHOW        To see the values of parameters that can be modified');
  2020.       write('':14, 'via the SET command. ');
  2021.       if (adj in [paritysym, localsym, ibmsym, escsym, debugsym,
  2022.                   filenamsym, filetypesym, filewarnsym, baudsym, 
  2023.                   emulatesym, systemsym, nullsym]) then begin
  2024.         writeln('For an explanation of the parameter,');
  2025.         writeln('':14, 'see the help for the matching SET command.'); write('':14)
  2026.       end; (* if *)
  2027.       if (adj in [allsym, versionsym, nullsym]) then begin
  2028.         writeln('Additional SHOW options are as follows:');
  2029.       end; (* if *)
  2030.       writeln;
  2031.       if (adj = nullsym) or (adj = allsym) then begin
  2032.         writeln('':14, 'ALL              Show all parameters.');
  2033.         writeln;
  2034.       end; (* if *)
  2035.       if (adj = nullsym) or (adj = versionsym) then begin
  2036.         writeln('':14, 'VERSION          Show version information.');
  2037.         writeln;
  2038.       end; (* if *)
  2039.     end; (* if *)
  2040.     if (noun = nullsym) then
  2041.         keypress;
  2042.  
  2043.     if (noun = nullsym) or (noun = takesym) then begin
  2044.       writeln('  TAKE        This command instructs Kermit to take further');
  2045.       writeln('':14, 'commands from a specified file.');
  2046.     end; (* if *)
  2047.     if (noun = nullsym) or (noun = comsym) then begin
  2048.       writeln('  COMMENT     Comments a TAKE file. (ignored)');
  2049.       writeln;
  2050.     end; (* if *)
  2051.     if (noun = nullsym) or (noun = logsym) then begin
  2052.       writeln('  LOG         This command opens a selected log file.');
  2053.       writeln('':14, 'LOG options are as follows:');
  2054.       writeln;
  2055.       if (adj = nullsym) or (adj = debugsym) then begin
  2056.         writeln('':14, 'DEBUG            open specified file for debug output.');
  2057.         writeln;
  2058.       end; (* if *)
  2059.     end; (* if *)
  2060.     if (noun = nullsym) or (noun = closesym) then begin
  2061.       writeln('  CLOSE       This command closes a selected log file previously');
  2062.       writeln('':14, 'opened via the LOG command.');
  2063.     end; (* if *)
  2064.   end; (* help4 *)
  2065.  
  2066. procedure help;
  2067. begin
  2068.   help1;
  2069.   help2;
  2070.   help3;
  2071.   help4
  2072. end; (* help *)
  2073.  
  2074. procedure hlp_version;
  2075.   
  2076.   begin
  2077.     writeln(my_version)
  2078.   end {hlp_version};
  2079.  
  2080. end. { unit helper }
  2081. {>>>> PARSER.TEXT}
  2082. (*$S+*)
  2083. unit parser;
  2084.  
  2085. INTERFACE
  2086.  
  2087. uses {$U kermglob.code} kermglob;
  2088.  
  2089. {Change log:
  2090. 13 May 89, V1.1: Fixed several bugs in parsing of HELP commands   RTC
  2091. 13 May 89, V1.1: Added parsing for COMMENT command
  2092. 30 Apr 89, V1.1: Added parsing for SET INTERFACE command   RTC
  2093. 26 Apr 89, V1.1: minor cleanups   RTC
  2094. 16 Apr 89, V1.1: Added BYE & FINISH command parsing       RTC
  2095. 14 Apr 89, V1.1: Added parsing for GET, PUT & SHOW VERSION commands   RTC
  2096. 13 Apr 89, V1.1: Added Version message       RTC
  2097. 14 Aug 88: Added parsing for LOG, CLOSE, and SET SYSTEM commands   RTC
  2098. 02 Jul 88: Added -NAMES, -TYPE, TAKE command parsing   RTC
  2099.  
  2100. }
  2101.  
  2102.    function parse: statustype;
  2103.  
  2104.    procedure initvocab;
  2105.    
  2106.    procedure par_version;
  2107.  
  2108.  
  2109. IMPLEMENTATION
  2110.  
  2111. uses
  2112.    {$U kermutil.code} kermutil;
  2113.  
  2114. const
  2115.   my_version = '   Parser Unit V1.1, 13 May 89';
  2116.  
  2117.  
  2118. procedure eatspaces(var s: string255);
  2119.  
  2120. var done: boolean;
  2121.     i: integer;
  2122.  
  2123.   begin
  2124.     done := (length(s) = 0);
  2125.     while not done do
  2126.       begin
  2127.         if s[1] = ' ' then
  2128.           begin
  2129.             i := length(s) - 1;
  2130.             s := copy(s,2,i);
  2131.             done := length(s) = 0
  2132.           end (* if *)
  2133.         else
  2134.             done := true
  2135.       end (* while *)
  2136.   end; (* eatspaces *)
  2137.  
  2138. procedure isolate_word(var line, s: string255);
  2139.  
  2140. var i: integer;
  2141.     done: boolean;
  2142.  
  2143.   begin
  2144.     done := false;
  2145.     i := 1;
  2146.     s := copy(' ',0,0);
  2147.     while (i <= length(line)) and not done do
  2148.       begin
  2149.         if line[i] = ' ' then
  2150.             done := true
  2151.         else
  2152.             s := concat(s,copy(line,i,1));
  2153.         i := i + 1;
  2154.       end; (* while *)
  2155.     line := copy(line,i,length(line)-i+1);
  2156.   end; (* isolate_word *)
  2157.  
  2158. function get_fn(var line, fn: string255): boolean;
  2159.  
  2160. var i, l: integer;
  2161.  
  2162.   begin
  2163.     get_fn := true;
  2164.     isolate_word(line, fn);
  2165.     l := length(fn);
  2166.     if (l < 1) then
  2167.         get_fn := false
  2168.   end; (* get_fn *)
  2169.  
  2170. function get_num( var line: string255; var n: integer ): boolean;
  2171.  
  2172. var
  2173.    numstr: string255;
  2174.    i, l: integer;
  2175. begin
  2176.    get_num := true;
  2177.    isolate_word( line, numstr );
  2178.    l := length(numstr);
  2179.    if (l>5) or (l<1) then begin
  2180.       n := 0;
  2181.       get_num := false
  2182.    end
  2183.    else begin
  2184.       n := 0; i := 1;
  2185.       numstr := concat( numstr, ' ' );
  2186.       while (numstr[i] in ['0'..'9']) do begin
  2187.          if n<(maxint div 10) then
  2188.             n := n*10 + ord( numstr[i] ) - ord( '0' );
  2189.          i := i + 1
  2190.       end
  2191.    end
  2192. end; { get_num }
  2193.  
  2194. function nextch(var ch: char): boolean;
  2195.  
  2196. var s: string255;
  2197.  
  2198.   begin
  2199.     isolate_word(line,s);
  2200.     if length(s) <> 1 then
  2201.         nextch := false
  2202.     else
  2203.       begin
  2204.         ch := s[1];
  2205.         nextch := true
  2206.       end (* else *)
  2207.   end; (* nextch *)
  2208.  
  2209. function parse(*: statustype*);
  2210.  
  2211. type states = (start, fin, get_filename, get_set_parm, get_parity, 
  2212.                get_on_off, get_f_type, get_char, get_show_parm, 
  2213.                get_help_show, get_int_type, get_naming, get_help_parm, 
  2214.                exitstate, get_baud, get_line, get_log_parm, get_help_log);
  2215.  
  2216. var status: statustype;
  2217.     word: vocab;
  2218.     state: states;
  2219.  
  2220. function get_a_sym(var word: vocab): statustype;
  2221.  
  2222. var i: vocab;
  2223.     s: string255;
  2224.     stat: statustype;
  2225.     done: boolean;
  2226.     matches: integer;
  2227.  
  2228.   begin
  2229.     eat_spaces(line);
  2230.     if length(line) = 0 then
  2231.         get_a_sym := ateol
  2232.     else
  2233.       begin
  2234.         stat := null;
  2235.         done := false;
  2236.         isolate_word(line,s);
  2237.         i := allsym;
  2238.         matches := 0;
  2239.         repeat
  2240.             if (pos(s,vocablist[i]) = 1) and (i in expected) then
  2241.               begin
  2242.                 matches := matches + 1;
  2243.                 word := i
  2244.               end
  2245.             else if (s[1] < vocablist[i,1]) then
  2246.                 done := true;
  2247.             if (i = versionsym) then
  2248.                 done := true
  2249.             else
  2250.                 i := succ(i)
  2251.         until (matches > 1) or done;
  2252.         if matches > 1 then
  2253.             stat := ambiguous
  2254.         else if (matches = 0) then
  2255.             stat := unrec;
  2256.         get_a_sym := stat
  2257.       end (* else *)
  2258.   end; (* get_a_sym *)
  2259.  
  2260.   begin
  2261.     state := start;
  2262.     parse := null;
  2263.     noun := nullsym;
  2264.     verb := nullsym;
  2265.     adj := nullsym;
  2266.     uppercase(line);
  2267.     repeat
  2268.         case state of
  2269.           start:
  2270.               begin
  2271.                 expected := [comsym, consym, exitsym, helpsym, quitsym,
  2272.                              logsym, closesym, getsym, putsym, byesym, finsym,
  2273.                              recsym, sendsym, setsym, showsym, takesym];
  2274.                 status := get_a_sym(verb);
  2275.                 if status = ateol then
  2276.                   begin
  2277.                     parse := null;
  2278.                     exit(parse)
  2279.                   end (* if *)
  2280.                 else if (status <> unrec) and (status <>  ambiguous) then
  2281.                     case verb of
  2282.                       comsym: state := get_line;
  2283.                       consym, exitsym, quitsym,
  2284.                       byesym, finsym, recsym: state := fin;
  2285.                       getsym, putsym,
  2286.                       sendsym, takesym: state := getfilename;
  2287.                       helpsym: state := get_help_parm;
  2288.                       logsym, closesym: state := get_log_param;
  2289.                       setsym: state := get_set_parm;
  2290.                       showsym: state := get_show_parm;
  2291.                     end (* case *)
  2292.               end; (* case start *)
  2293.           fin:
  2294.               begin
  2295.                 expected := [];
  2296.                 status := get_a_sym(verb);
  2297.                 if status = ateol then
  2298.                   begin
  2299.                     parse := null;
  2300.                     exit(parse)
  2301.                   end (* if status *)
  2302.                 else
  2303.                     status := unconfirmed
  2304.               end; (* case fin *)
  2305.           getfilename:
  2306.             begin
  2307.               expected := [];
  2308.               if getfn(line,xfilename) then
  2309.                 begin
  2310.                   status := null;
  2311.                   state := fin
  2312.                 end (* if *)
  2313.               else
  2314.                   status := fnexpected
  2315.             end; (* case get file name *)
  2316.           get_set_parm:
  2317.               begin
  2318.                 expected := [paritysym, localsym, ibmsym, emulatesym, 
  2319.                              escsym, debugsym, filenamsym, filetypesym,
  2320.                              intsym, filewarnsym, baudsym, systemsym];
  2321.                 status := get_a_sym(noun);
  2322.                 if status = ateol then
  2323.                     status := parm_expected
  2324.                 else if (status <> unrec) and (status <>  ambiguous) then
  2325.                     case noun of
  2326.                       paritysym: state := get_parity;
  2327.                       localsym: state := get_on_off;
  2328.                       ibmsym: state := get_on_off;
  2329.                       emulatesym: state := get_on_off;
  2330.                       escsym: state := getchar;
  2331.                       debugsym: state := get_on_off;
  2332.                       filenamsym : state := get_naming;
  2333.                       filetypesym : state := get_f_type;
  2334.                       filewarnsym: state := get_on_off;
  2335.                       intsym: state := get_int_type;
  2336.                       baudsym: state := get_baud;
  2337.                       systemsym: state := get_line
  2338.                     end (* case *)
  2339.             end; (* case get_set_parm *)
  2340.           get_log_parm:
  2341.               begin
  2342.                 expected := [debugsym];
  2343.                 status := get_a_sym(adj);
  2344.                 if status = ateol then
  2345.                     status := parm_expected
  2346.                 else if (status <> unrec) and (status <> ambiguous) then
  2347.                     if verb = logsym
  2348.                       then state := getfilename
  2349.                       else state := fin
  2350.               end; (* case get_log_parm *)
  2351.           get_line:
  2352.               begin
  2353.                 eat_spaces(line);
  2354.                 parse := null;
  2355.                 exit(parse)
  2356.               end; {case get_line}
  2357.           get_parity, get_naming, get_int_type, get_on_off, get_f_type:
  2358.               begin
  2359.                 case state of
  2360.                   get_parity:   expected := [marksym, spacesym,
  2361.                                              nonesym, evensym, oddsym];
  2362.                   get_naming:   expected := [convsym, litsym];
  2363.                   get_int_type: expected := [kermitsym, ucsdsym];
  2364.                   get_on_off:   expected := [onsym, offsym];
  2365.                   get_f_type:   expected := [binsym, textsym];
  2366.                 end {case state};
  2367.                 status := get_a_sym(adj);
  2368.                 if status = ateol then
  2369.                     status := parm_expected
  2370.                 else if (status <> unrec) and (status <> ambiguous) then
  2371.                     state := fin
  2372.               end; (* case get_parity  *)
  2373.           get_baud:
  2374.              begin
  2375.                expected := [];
  2376.                if get_num( line, newbaud ) then begin
  2377.                   status := null; state := fin
  2378.                end
  2379.                else begin
  2380.                   newbaud := 0;
  2381.                   status := parm_expected
  2382.                end
  2383.              end; (* case get_baud *)
  2384.           get_char:
  2385.               if nextch(newescchar) then
  2386.                  state := fin
  2387.               else
  2388.                  status := ch_expected;
  2389.           get_show_parm:
  2390.               begin
  2391.                 expected := [allsym, paritysym, localsym, ibmsym, 
  2392.                              emulatesym, escsym, debugsym, 
  2393.                              filenamsym, filetypesym, filewarnsym, 
  2394.                              baudsym, systemsym, versionsym];
  2395.                 status := get_a_sym(noun);
  2396.                 if status = ateol then
  2397.                     status := parm_expected
  2398.                 else if (status <> unrec) and (status <>  ambiguous) then
  2399.                     state := fin
  2400.               end; (* case get_show_parm *)
  2401.           get_help_show, get_help_log:
  2402.               begin
  2403.                 case noun of
  2404.                   logsym, closesym: 
  2405.                     expected := [debugsym];
  2406.                   setsym: 
  2407.                     expected := [paritysym, localsym, ibmsym, escsym,
  2408.                                  intsym, debugsym, filenamsym, filetypesym, 
  2409.                                  filewarnsym, baudsym, emulatesym, systemsym];
  2410.                   showsym:
  2411.                     expected := [paritysym, localsym, ibmsym, escsym,
  2412.                                  debugsym, filenamsym, filetypesym, 
  2413.                                  filewarnsym, baudsym, emulatesym, systemsym,
  2414.                                  allsym, versionsym];
  2415.                 end {case noun};
  2416.                 status := get_a_sym(adj);
  2417.                 if (status = at_eol) then
  2418.                   begin
  2419.                     status := null;
  2420.                     state := fin
  2421.                   end
  2422.                 else if (status <> unrec) and (status <>  ambiguous) then
  2423.                     state := fin
  2424.               end; (* case get_help_show *)
  2425.           get_help_parm:
  2426.               begin
  2427.                 expected := [consym, exitsym, helpsym, quitsym, recsym,
  2428.                              comsym, getsym, putsym, byesym, finsym, takesym,
  2429.                              logsym, closesym, sendsym, setsym, showsym];
  2430.                 status := get_a_sym(noun);
  2431.                 if status = ateol then
  2432.                   begin
  2433.                     parse := null;
  2434.                     exit(parse)
  2435.                   end;
  2436.                 if (status <> unrec) and (status <>  ambiguous) then
  2437.                     case noun of
  2438.                       consym, comsym, getsym, putsym,
  2439.                       sendsym, finsym, byesym, takesym,
  2440.                       recsym: state := fin;
  2441.                       closesym, logsym: state := get_help_log;
  2442.                       showsym, setsym: state := get_help_show;
  2443.                       helpsym: state := fin;
  2444.                       exitsym, quitsym: state := fin;
  2445.                     end (* case *)
  2446.               end; (* case get_help_show *)
  2447.         end (* case *)
  2448.     until (status <> null);
  2449.     parse := status
  2450.   end; (* parse *)
  2451.  
  2452. procedure initvocab;
  2453.  
  2454. var i: integer;
  2455.  
  2456.   begin
  2457.     vocablist[allsym] :=        'ALL';
  2458.     vocablist[baudsym] :=       'BAUD';
  2459.     vocablist[binsym] :=        'BINARY';
  2460.     vocablist[byesym] :=        'BYE';
  2461.     vocablist[closesym] :=      'CLOSE';
  2462.     vocablist[comsym] :=        'COMMENT';
  2463.     vocablist[consym] :=        'CONNECT';
  2464.     vocablist[convsym] :=       'CONVERTED';
  2465.     vocablist[debugsym] :=      'DEBUG';
  2466.     vocablist[emulatesym] :=    'EMULATE';
  2467.     vocablist[escsym] :=        'ESCAPE';
  2468.     vocablist[evensym] :=       'EVEN';
  2469.     vocablist[exitsym] :=       'EXIT';
  2470.     vocablist[filenamsym] :=    'FILE-NAMES';
  2471.     vocablist[filetypesym] :=   'FILE-TYPE';
  2472.     vocablist[filewarnsym] :=   'FILE-WARNING';
  2473.     vocablist[finsym] :=        'FINISH';
  2474.     vocablist[getsym] :=        'GET';
  2475.     vocablist[helpsym] :=       'HELP';
  2476.     vocablist[ibmsym] :=        'IBM';
  2477.     vocablist[intsym] :=        'INTERFACE';
  2478.     vocablist[kermitsym] :=     'KERMIT';
  2479.     vocablist[litsym] :=        'LITERAL';
  2480.     vocablist[localsym] :=      'LOCAL-ECHO';
  2481.     vocablist[logsym] :=        'LOG';
  2482.     vocablist[marksym] :=       'MARK';
  2483.     vocablist[nonesym] :=       'NONE';
  2484.     vocablist[oddsym] :=        'ODD';
  2485.     vocablist[offsym] :=        'OFF';
  2486.     vocablist[onsym] :=         'ON';
  2487.     vocablist[paritysym] :=     'PARITY';
  2488.     vocablist[putsym] :=        'PUT';
  2489.     vocablist[quitsym] :=       'QUIT';
  2490.     vocablist[recsym] :=        'RECEIVE';
  2491.     vocablist[sendsym] :=       'SEND';
  2492.     vocablist[setsym] :=        'SET';
  2493.     vocablist[showsym] :=       'SHOW';
  2494.     vocablist[spacesym] :=      'SPACE';
  2495.     vocablist[systemsym] :=     'SYSTEM-ID';
  2496.     vocablist[takesym] :=       'TAKE';
  2497.     vocablist[textsym] :=       'TEXT';
  2498.     vocablist[ucsdsym] :=       'UCSD';
  2499.     vocablist[versionsym] :=    'VERSION';
  2500.   end; (* initvocab *)
  2501.  
  2502. procedure par_version;
  2503.   
  2504.   begin
  2505.     writeln(my_version)
  2506.   end {par_version};
  2507.   
  2508. end. (* end of unit *)
  2509.  
  2510. {>>>> INTFUTIL.TEXT}
  2511. interface
  2512.  
  2513. {Change log:
  2514. 30 Apr 89, V1.1: Extracted from KERMUTIL   RTC
  2515. }
  2516.    
  2517.    uses
  2518.      {$U kermglob.code} kermglob;
  2519.    
  2520.    procedure fill_parity_array;
  2521.    
  2522.    procedure set_parms;
  2523.    
  2524.    procedure show_parms;
  2525.    
  2526.    procedure connect;
  2527.    
  2528.    function read_ch(unitno: integer; var ch: char): boolean;
  2529.  
  2530.    procedure read_str(unitno:integer; var s: string255);
  2531.  
  2532.    procedure echo(ch: char);
  2533.  
  2534.    procedure clear_buf(unitno:integer);
  2535.  
  2536.    function aand(x,y: integer): integer;
  2537.  
  2538.    function aor(x,y: integer): integer;
  2539.  
  2540.    function xor(x,y: integer): integer;
  2541.  
  2542.    procedure uppercase(var s: string255);
  2543.  
  2544.    procedure error(p: packettype; len: integer);
  2545.  
  2546.    procedure io_error(i: integer);
  2547.  
  2548.    procedure debugwrite(s: string255);
  2549.  
  2550.    procedure debugint(s: string255; i: integer);
  2551.  
  2552.    function min(x,y: integer): integer;
  2553.  
  2554.    function tochar(ch: char): char;
  2555.  
  2556.    function unchar(ch: char): char;
  2557.  
  2558.    function ctl(ch: char): char;
  2559.  
  2560.    function getch(var r: char): boolean;
  2561.  
  2562.    function getsoh: boolean;
  2563.  
  2564.    function getfil(filename: string255): boolean;
  2565.  
  2566.    procedure send_brk;
  2567.  
  2568.    function setup_comm : boolean;        {changed 31 Jul 88, RTC}
  2569.    
  2570.    procedure flush_comm;                {added 16 Apr 89, RTC}
  2571.  
  2572.    procedure write_bool(s: string255; b: boolean);
  2573.    
  2574.    procedure write_ch(unitno: integer; ch: char );
  2575.  
  2576.    procedure writescreen(s: string255);
  2577.  
  2578.    procedure refresh_screen(numtry, num: integer);
  2579.    
  2580.    procedure set_timer(t : integer);    {added 26 Apr 89, RTC}
  2581.    
  2582.    function timeout : boolean;          {added 26 Apr 89, RTC}
  2583.    
  2584.    procedure utl_version;
  2585.  
  2586. implementation
  2587.  
  2588. {>>>> FAKEUTIL.TEXT}
  2589.  
  2590. unit kermutil;
  2591.  
  2592. { Change log:
  2593. 30 Apr 89, V1.1: Created Fake version of KERMUTIL   RTC
  2594. }
  2595.    
  2596. {$I intfutil.text}
  2597.  
  2598. procedure fill_parity_array;
  2599.   begin end; (* fill_parity_array *)
  2600.  
  2601. procedure write_bool{s: string255; b: boolean};
  2602.   begin end; (* write_bool *)
  2603.  
  2604. procedure show_parms;
  2605.   begin end; (* show_sym *)
  2606.  
  2607. procedure set_parms;
  2608.   begin end; (* set_parms *)
  2609.  
  2610. procedure connect;
  2611.   begin (* connect *) end; (* connect *)
  2612.  
  2613. procedure uppercase(*var s: string255*);
  2614.   begin end; (* uppercase *)
  2615.  
  2616. function read_ch(*unitno:integer; var ch: char): boolean*);
  2617.   begin end; (* read_ch *)
  2618.  
  2619. procedure write_ch(*unitno: integer; ch: char*);
  2620.   begin end;
  2621.  
  2622. procedure read_str(*unitno:integer; var s: string255*);
  2623.   begin end; (* read_str *)
  2624.  
  2625. procedure clear_buf(*unitno:integer*);
  2626.   begin end;
  2627.   
  2628. procedure send_brk;
  2629.   begin end;
  2630.  
  2631. function setup_comm{ : boolean};
  2632.   begin end;
  2633.    
  2634. procedure flush_comm;                {added 16 Apr 89, RTC}
  2635.   begin {flush_comm} end {flush_comm};
  2636.  
  2637. function aand(*x,y: integer): integer*);
  2638.   begin end; (* aand *)
  2639.  
  2640. function aor(*x,y: integer): integer*);
  2641.   begin end; (* aor *)
  2642.  
  2643. function xor(*x,y: integer): integer*);
  2644.   begin end; (* xor *)
  2645.  
  2646. procedure error(*p: packettype; len: integer*);
  2647.   begin end; (* error *)
  2648.  
  2649. procedure io_error(*i: integer*);
  2650.   begin end; (* io_error *)
  2651.  
  2652. procedure debugwrite(*s: string255*);
  2653.   begin end; (* debugwrite *)
  2654.  
  2655. procedure debugint(*s: string255; i: integer*);
  2656.   begin end; (* debugint *)
  2657.  
  2658. function min(*x,y: integer): integer*);
  2659.   begin end; (* min *)
  2660.  
  2661. function tochar(*ch: char): char*);
  2662.   begin end; (* tochar *)
  2663.  
  2664. function unchar(*ch: char): char*);
  2665.   begin end; (* unchar *)
  2666.  
  2667. function ctl(*ch: char): char*);
  2668.   begin end; (* ctl *)
  2669.  
  2670. procedure echo(*ch: char*);
  2671.   begin end; (* echo *)
  2672.  
  2673. function getch(*var r: char): boolean*);
  2674.   begin end; (* getch *)
  2675.  
  2676. function getsoh(*: boolean*);
  2677.   begin end; (* getsoh *)
  2678.  
  2679. function getfil(*filename: string255): boolean*);
  2680.   begin end; (* getfil *)
  2681.  
  2682. procedure writescreen(*s: string255*);
  2683.   begin end; (* writescreen *)
  2684.  
  2685. procedure refresh_screen(*numtry, num: integer*);
  2686.   begin end; (* refresh_screen *)
  2687.  
  2688. procedure set_timer{t : integer};    {added 26 Apr 89, RTC}
  2689.   begin {set_timer} end {set_timer};
  2690.  
  2691. function timeout {: boolean};        {added 26 Apr 89, RTC}
  2692.   begin {timeout} end {timeout};
  2693.  
  2694. procedure utl_version;
  2695.   begin end {utl_version};
  2696.  
  2697. begin { body of unit kermutil }
  2698.    { initialization code }
  2699.    ***;
  2700.    { termination code }
  2701. end. { fakeutil }
  2702. {>>>> KERMUTIL.TEXT}
  2703. {$D OS_ERHDL+}    { indicates to compile to use Pecan's errorhandler unit }
  2704. {$D OS_TIMER+}    { indicates to compile to use TIME() for timeouts }
  2705.  
  2706. unit kermutil;
  2707.  
  2708. { Change log:
  2709. 13 May 89, V1.1: Eliminated "int_bool_rec" & misc cleanups   RTC
  2710. 30 Apr 89, V1.1: Moved set/show & connect from kermit to here   RTC
  2711. 26 Apr 89, V1.1: Added support for TIMEr controlled timeouts   RTC
  2712. 16 Apr 89, V1.1: Added procedure flush_comm to Flush REMOTE:    RTC
  2713. 13 Apr 89, V1.1: Added Version message          RTC
  2714. 17 Aug 88: Fixed missing EOLN's problem in debf    RTC
  2715. 14 Aug 88: Fixed the debug messages to all go to debf      RTC
  2716. 31 Jul 88: Modified setup_comm to funct., updated io_error.    RTC
  2717. 10 Jul 88: Converted to using screenops unit     RTC
  2718. 02 Jul 88: Misc cleanup, eliminated char_int_rec, etc.   RTC
  2719. 26 Jun 88 Patched Unitwrite problem in Echo   RTC
  2720. 26 Jun 88 Modified read_ch to use cr_getkb    RTC
  2721.  
  2722.         13 May 84: Use KERNEL's syscom record for screen control -sp-
  2723. }
  2724.    
  2725. {$I intfutil.text}
  2726.  
  2727. uses {$U *system.library} screenops, {RTC, 10 Jul 88}
  2728.      {$U kermenus.code} kermenus,
  2729.      {$U kermpack.code} kermpack (pak_version),
  2730.      {$U helper.code} helper (hlp_version),
  2731.      {$U parser.code} parser (par_version),
  2732.      {$U sender.code} sender (sen_version),
  2733.      {$U receiver.code} receiver (rec_version),
  2734.      {$U client.code} client (cli_version),
  2735.      {$U remunit.code} remunit,  {SP, 1/14/84}
  2736.      {$U syslibr:kernel.code} kernel (syscom,version) {$B OS_ERHDL+},
  2737.      {$U syslibr:errorhandl.code} error_handling {$E OS_ERHDL+};
  2738.    
  2739. const
  2740.   my_version = '   Kermutil Unit V1.1, 13 May 89';
  2741.  
  2742. type
  2743.   time_value = integer[10];
  2744.  
  2745. var
  2746.   old_flush, old_stop: char;
  2747.   time_limit : time_value;
  2748.  
  2749. {$I setshow.text}
  2750.  
  2751. procedure connect;
  2752.  
  2753. (* connect to remote host and transceive *)
  2754.  
  2755. var ch: char;
  2756.     close: boolean;
  2757.  
  2758.   procedure read_esc;
  2759.  
  2760.   (* read character after esc char and interpret it *)
  2761.  
  2762.     begin
  2763.       repeat
  2764.       until read_ch(keyport,ch);       (* wait until they've typed something in *)
  2765.       if (ch in ['a'..'z']) then  (* uppercase it *)
  2766.           ch := chr(ord(ch) - ord('a') + ord('A'));
  2767.       if ch in ['B','C','S','?'] then
  2768.           case ch of
  2769.               'B': sendbrk;       (* B: send a break to the IBM *)
  2770.               'C': close := true; (* C: end connection *)
  2771.               'S': begin          (* S: show status *)
  2772.                       noun := allsym;
  2773.                       showparms
  2774.                    end; (* S *)
  2775.               '?': begin          (* ?: show options *)
  2776.                   writeln
  2777. ('B    Send a BREAK signal.');
  2778.                   writeln
  2779. ('C    Close Connection, return to KERMIT-UCSD command level.');
  2780.                   writeln
  2781. ('S    Show Status of connection');
  2782.                   writeln
  2783. ('?    Print this list');
  2784.                   writeln
  2785. ('^',ctl(esc_char),'   send the escape character itself to the remote host.')
  2786.                 end; (* ? *)
  2787.             end (* case *)
  2788.       else if ch = esc_char then  (* ESC-char: send it out *)
  2789.         begin
  2790.           if half_duplex then
  2791.               write(ch); { changed from echo() by SP }
  2792.           write_ch(oport,ch)
  2793.         end (* else if *)
  2794.       else                        (* anything else: ignore *)
  2795.           write(chr(bell))
  2796.     end; (* read_esc *)
  2797.  
  2798.   begin (* connect *)
  2799.     clear_buf(keyport);                    (* empty keyboard buffer *)
  2800.     clear_buf(inport);                    (* empty remote input buffer *)
  2801.     writeln('Connecting to host...type CTRL-',ctl(esc_char),' C to exit');
  2802.     close := false;
  2803.     repeat
  2804.         if read_ch(inport,ch) then        (* if char from host then *)
  2805.             echo(ch);                   (* echo it *)
  2806.  
  2807.         if read_ch(keyport,ch) then        (* if char from keyboard then *)
  2808.             if ch <> esc_char then      (* if not ESC-char then *)
  2809.               begin
  2810.                 if half_duplex then       (* echo it if half-duplex *)
  2811.                     write(ch); { changed from echo() by sp }
  2812.                 write_ch(oport,ch)     (* send it out the port *)
  2813.               end (* if *)
  2814.             else (* ch = esc_char *)    (* else is ESC-char so *)
  2815.               read_esc;                   (* interpret next char *)
  2816.     until close;                      (* if still connected, get more *)
  2817.     writeln('Disconnected')
  2818.   end; (* connect *)
  2819.  
  2820. procedure uppercase(*var s: string255*);
  2821.  
  2822. var i: integer;
  2823.  
  2824.   begin
  2825.     for i := 1 to length(s) do
  2826.         if s[i] in ['a'..'z'] then
  2827.             s[i] := chr(ord(s[i]) - ord('a') + ord('A'))
  2828.   end; (* uppercase *)
  2829.  
  2830.  
  2831. function read_ch(*unitno:integer; var ch: char): boolean*);
  2832.  
  2833. (* read a character from an input queue *)
  2834. var
  2835.    ready: boolean;
  2836.  
  2837.   begin
  2838.     if unitno=keyport then
  2839.        ready := cr_kbstat
  2840.     else if unitno=inport then
  2841.        ready := cr_remstat
  2842.     else
  2843.        ready := false;
  2844.     if ready then            (* if a char there *)
  2845.        if unitno=keyport then
  2846.           ch := cr_getkb
  2847.        else
  2848.           ch := cr_getrem;
  2849.     read_ch := ready
  2850.   end; (* read_ch *)
  2851.  
  2852. procedure write_ch(*unitno: integer; ch: char*);
  2853. begin
  2854.    if unitno=oport then
  2855.       cr_putrem( ch )
  2856. end;
  2857.  
  2858.  
  2859. procedure read_str(*unitno:integer; var s: string255*);
  2860.  
  2861. (* acts like readln(s) but takes input from input queue *)
  2862.  
  2863. var i: integer;
  2864.  
  2865.   begin
  2866.     i := 0;
  2867.     s := copy('',0,0);
  2868.     repeat
  2869.       repeat                              (* get a character *)
  2870.       until read_ch(unitno,ch);
  2871.       if (ord(ch) = backspace) then       (* if it's a backspace then *)
  2872.         begin
  2873.           if (i > 0) then                   (* if not at beginning of line *)
  2874.             begin
  2875.               write(ch);                      (* go back a space on screen *)
  2876.               write(' ');                     (* erase char on screen *)
  2877.               write(ch);                      (* go back a space again *)
  2878.               i := i - 1;                     (* adjust string counter *)
  2879.               s := copy(s,1,i)                (* adjust string *)
  2880.             end (* if *)
  2881.         end (* if *)
  2882.       else if (ord(ch) <> eoln_sym) then  (* otherwise if not at eoln  then *)
  2883.         begin
  2884.           write(ch);                        (* echo char on screen *)
  2885.           i := i + 1;                       (* inc string counter *)
  2886.           s := concat(s,' ');
  2887.           s[i] := ch;                       (* put char in string *)
  2888.         end; (* if *)
  2889.     until (ord(ch) = eoln_sym);           (* if not eoln, get another char *)
  2890.     s := copy(s,1,i);                     (* correct string length *)
  2891.     writeln                               (* write a line on the screen *)
  2892.   end; (* read_str *)
  2893.  
  2894.  
  2895. procedure clear_buf(*unitno:integer*);
  2896. { modified by SP }
  2897. begin
  2898.    if unitno=keyport then
  2899.       unitclear( unitno )
  2900. end;
  2901.  
  2902.  
  2903. procedure send_brk;
  2904. begin
  2905.    cr_break
  2906. end;
  2907.  
  2908.  
  2909. function setup_comm{ : boolean};
  2910. { SP, 14 Jan 84 }
  2911. var
  2912.    result: cr_baud_result;
  2913. begin
  2914.    setup_comm := false;
  2915.    cr_setcommunications(false,
  2916.                         false,
  2917.                         baud,
  2918.                         8,
  2919.                         1,
  2920.                         cr_orig,
  2921.                         system_id,
  2922.                         result );
  2923.    case result of
  2924.      CR_bad_parameter :
  2925.          writeln('Bad Parameter, # Bits or Parity wrong');
  2926.      CR_bad_rate :
  2927.          writeln('Bad Baud Rate selection');
  2928.      CR_set_OK :
  2929.          setup_comm := true;
  2930.      CR_select_not_supported :
  2931.          writeln('Hardware does not support Baud selection')
  2932.    end {case}
  2933. end;
  2934.    
  2935. procedure flush_comm;                {added 16 Apr 89, RTC}
  2936.   
  2937.   var
  2938.     ch : char;
  2939.   
  2940.   begin {flush_comm}
  2941.     while CR_remstat do
  2942.       ch := CR_getrem   {flush all characters in REMOTE port}
  2943.   end {flush_comm};
  2944.  
  2945. function aand(*x,y: integer): integer*);
  2946.  
  2947. (* arithmetic and--takes 2 integers and ands them, yeilding an integer *)
  2948.  
  2949.   begin
  2950.     aand := ord(odd(x) and odd(y));  (* use as booleans to 'and' them *)
  2951.   end; (* aand *)
  2952.  
  2953.  
  2954. function aor(*x,y: integer): integer*);
  2955.  
  2956. (* arithmetic or *)
  2957.  
  2958.   begin
  2959.     aor := ord(odd(x) or odd(y));   (* use as booleans to 'or' them *)
  2960.   end; (* aor *)
  2961.  
  2962. function xor(*x,y: integer): integer*);
  2963.  
  2964. (* exclusive or *)
  2965.  
  2966.   begin
  2967.     xor := ord( (odd(x) or odd(y)) and not(odd(x) and odd(y)) );
  2968.   end; (* xor *)
  2969.  
  2970. procedure error(*p: packettype; len: integer*);
  2971.  
  2972. (* writes error message sent by remote host *)
  2973.  
  2974. var i: integer;
  2975.  
  2976.   begin
  2977.     gotoxy(0,errorline);
  2978.     for i := 0 to len-1 do
  2979.         write(p[i]);
  2980.     gotoxy(0,promptline);
  2981.   end; (* error *)
  2982.  
  2983. procedure io_error(*i: integer*);
  2984.   
  2985.   var
  2986.     message : string;
  2987.     
  2988.   begin
  2989.     SC_erase_to_EOL( 0, errorline );
  2990.     {$B OS_ERHDL+}
  2991.     IOR_to_message(i,message);
  2992.     {$E OS_ERHDL+} {$B OS_ERHDL-}
  2993.     case i of
  2994.         0: message := 'No error';
  2995.         1: message := 'Bad Block, Parity error (CRC)';
  2996.         2: message := 'Bad Unit Number';
  2997.         3: message := 'Bad I/O request, Illegal operation';
  2998.         4: message := 'Undefined hardware error';
  2999.         5: message := 'Lost unit, Volume is no longer on-line';
  3000.         6: message := 'Lost file, File is no longer in directory';
  3001.         7: message := 'Bad Title, Illegal file name';
  3002.         8: message := 'No room, insufficient space';
  3003.         9: message := 'No unit, No such volume on line';
  3004.         10: message := 'No file, No such file on volume';
  3005.         11: message := 'Duplicate file';
  3006.         12: message := 'Not closed, attempt to open an open file';
  3007.         13: message := 'Not open, attempt to access a closed file';
  3008.         14: message := 'Bad format, error in reading real or integer';
  3009.         15: message := 'Queue overflow';
  3010.         16: message := 'Write Protected volume';
  3011.         17: message := 'Illegal Block';
  3012.         18: message := 'Illegal Buffer for low-level I/O';
  3013.         19: message := 'Illegal Size or Range of File Attribute';
  3014.         20: message := 'Attempted read past End of File';
  3015.       end; (* case *)
  3016.       if i >= 128 then
  3017.         begin
  3018.           i := i - 128; message := '0';
  3019.           while i > 0 do
  3020.             begin
  3021.               message[1] := chr(ord('0') + i mod 10);
  3022.               message := concat(' ',message);
  3023.               i := i div 10
  3024.             end;
  3025.           message := concat('Host Operating System Error #',message)
  3026.         end;
  3027.     {$E OS_ERHDL-}
  3028.     writeln(message);
  3029.     gotoxy(0,promptline)
  3030.   end; (* io_error *)
  3031.  
  3032. procedure debugwrite(*s: string255*);
  3033.  
  3034. (* writes a debugging message *)
  3035. var i: integer;
  3036.  
  3037.   begin
  3038.     if debug then
  3039.       begin
  3040.         SC_erase_to_EOL(0,debugline);
  3041.         gotoxy(0,pred(debugline)); writeln(debf);
  3042.         write(debf,s);
  3043.         for i := 1 to 2000 do ;                (* write debugging message *)
  3044.       end (* if debug *)
  3045.   end; (* debugwrite *)
  3046.  
  3047. procedure debugint(*s: string255; i: integer*);
  3048.  
  3049. (* write a debugging message and an integer *)
  3050.  
  3051.   begin
  3052.     if debug then
  3053.       begin
  3054.         debugwrite(s);
  3055.         write(debf,i)
  3056.       end (* if debug *)
  3057.   end; (* debugint *)
  3058.  
  3059. function min(*x,y: integer): integer*);
  3060.  
  3061. (* returns smaller of two integers *)
  3062.  
  3063.   begin
  3064.     if x < y then
  3065.         min := x
  3066.     else
  3067.         min := y
  3068.   end; (* min *)
  3069.  
  3070. function tochar(*ch: char): char*);
  3071.  
  3072. (* tochar converts a control character to a printable one by adding space *)
  3073.  
  3074.   begin
  3075.     tochar := chr(ord(ch) + ord(' '))
  3076.   end; (* tochar *)
  3077.  
  3078. function unchar(*ch: char): char*);
  3079.  
  3080. (* unchar undoes tochar *)
  3081.  
  3082.   begin
  3083.     unchar := chr(ord(ch) - ord(' '))
  3084.   end; (* unchar *)
  3085.  
  3086. function ctl(*ch: char): char*);
  3087.  
  3088. (* ctl toggles control bit: ^A becomes A, A becomes ^A *)
  3089.  
  3090.   begin
  3091.     ctl := chr(xor(ord(ch),64))
  3092.   end; (* ctl *)
  3093.  
  3094. procedure echo(*ch: char*);
  3095.  
  3096. (* echos a character on the screen *)
  3097.  
  3098. var cursorx, cursory:integer;
  3099.     ch_buf : packed array [0..1] of char;
  3100.  
  3101. { The DataMedia emulation is by John Socha. }
  3102. begin
  3103.    ch := chr(aand(ord(ch),127)); (* mask off parity bit *)
  3104.    ch_buf[0] := ch;     {for unitwrite portability      RTC}
  3105.    
  3106.    if emulating and (ord(ch) in [30,25,28,31,29,11]) then
  3107.       case ord(ch) of
  3108.          { Datamedia 1520 emulation }
  3109.          { rs }30: begin
  3110.                       { allow timeout while waiting for coordinates
  3111.                         so computer doesn't freeze }
  3112.                       set_timer(2);
  3113.                       repeat
  3114.                       until read_ch( inport, ch ) or timeout;
  3115.                       if not timeout then begin
  3116.                          cursorx:=ord(ch)-32;
  3117.                          repeat
  3118.                          until read_ch( inport, ch ) or timeout;
  3119.                          if not timeout then begin
  3120.                             cursory:=ord(ch)-32;
  3121.                             gotoxy(cursorx,cursory)
  3122.                          end
  3123.                       end
  3124.                    end;
  3125.          { em }25: SC_home;
  3126.          { fs }28: SC_right;
  3127.          { us }31: SC_up;
  3128.          { gs }29: SC_erase_to_EOL(SC_find_X,SC_find_Y);
  3129.          { vt }11: SC_eras_eos(SC_find_X,SC_find_Y)
  3130.       end
  3131.     else
  3132.        unitwrite(1,ch_buf[0],1,,12)  { the 12 eliminates DLE & CR expansion }
  3133.   end; (* echo *)
  3134.  
  3135.  
  3136. function getch(*var r: char): boolean*);
  3137.  
  3138. (* gets a character, strips parity, returns true if it got a char which *)
  3139. (* isn't Kermit SOH, false if it gets SOH or nothing after timeout *)
  3140.  
  3141.   begin
  3142.     getch := false;
  3143.     repeat
  3144.     until (read_ch(inport,r)) or timeout;       (* wait for a character *)
  3145.     if timeout then                             (* if wait too long then *)
  3146.         exit(getch);                            (* get out of here *)
  3147.     if parity <> nopar
  3148.       then r := chr(aand(ord(r),127));          (* strip parity from char *)
  3149.     getch := (r <> chr(soh));                   (* return true if not SOH *)
  3150.   end; (* getch *)
  3151.  
  3152.  
  3153. function getsoh(*: boolean*);
  3154.  
  3155. (* reads characters until it finds an SOH; returns false if has timed out *)
  3156.  
  3157. var ch: char;
  3158.  
  3159.   begin
  3160.     getsoh := true;
  3161.     repeat
  3162.       repeat
  3163.       until (read_ch(inport,ch)) or timeout; (* wait for a character *)
  3164.       if timeout then
  3165.         begin
  3166.             getsoh := false;
  3167.             exit(getsoh)
  3168.           end; (* if *)
  3169.         ch := chr(aand(ord(ch),127));            (* strip parity of char *)
  3170.     until (ch = chr(SOH))                        (* if not SOH, get more *)
  3171.   end; (* getsoh *)
  3172.  
  3173.  
  3174. function getfil(*filename: string255): boolean*);
  3175.  
  3176. (* opens a file for writing *)
  3177.  
  3178.   begin
  3179.     (*$I-*) (* turn i/o checking off *)
  3180.     if f_is_binary
  3181.       then
  3182.         begin
  3183.           rewrite(b_file,filename);
  3184.           bufpos := 1           {new file... nothing in buffer}
  3185.         end
  3186.       else rewrite(t_file,filename);
  3187.     (*$I-*) (* turn i/o checking on *)
  3188.     getfil := (ioresult = 0)
  3189.   end; (* getfil *)
  3190.  
  3191.  
  3192. procedure writescreen(*s: string255*);
  3193.  
  3194. (* sets up the screen for receiving or sending files *)
  3195.  
  3196. begin
  3197.    page(output);
  3198.    gotoxy(0,titleline);
  3199.    write('            Kermit UCSD p-System, Version ', version );
  3200.    gotoxy(statuspos,statusline);
  3201.    write(s);
  3202.    gotoxy(0,packetline);
  3203.    write('Number of Packets: ');
  3204.    gotoxy(0,retryline);
  3205.    write('Number of Tries: ');
  3206.    gotoxy(0,fileline);
  3207.    write('File Name: ');
  3208. end; (* writescreen *)
  3209.  
  3210.  
  3211. procedure refresh_screen(*numtry, num: integer*);
  3212.  
  3213. (* keeps track of packet count on screen *)
  3214.  
  3215. begin
  3216.    gotoxy(retrypos,retryline);
  3217.    write(numtry: 5);
  3218.    gotoxy(packetpos,packetline);
  3219.    write(num: 5)
  3220. end; (* refresh_screen *)
  3221.  
  3222. {$B OS_TIMER+}
  3223. procedure long_time(var t : time_value);
  3224.   
  3225.   {this procedure converts the "dual integer" values returned by time()
  3226.    to a single "long integer" value, which it returns to the caller}
  3227.   
  3228.   var
  3229.     i : 0..1;
  3230.     hl : array [0..1] of integer;
  3231.   
  3232.   begin {long_time}
  3233.     t := 0; time(hl[0],hl[1]);
  3234.     for i := 0 to 1 do
  3235.       begin
  3236.         if hl[i] < 0 then t := t + 1;
  3237.         t := 65536*t + hl[i]
  3238.       end
  3239.   end {long_time};
  3240. {$E OS_TIMER+}
  3241.  
  3242. procedure set_timer{t : integer};    {added 26 Apr 89, RTC}
  3243.   
  3244.   {$B OS_TIMER-}
  3245.   const counts_per_second = 1000;        {WARNING!! implementation dependant}
  3246.   {$E OS_TIMER-}
  3247.   
  3248.   var long_t : time_value;
  3249.   
  3250.   begin {set_timer}
  3251.     long_t := t; {convert to long format}
  3252.     {$B OS_TIMER+}
  3253.     long_time(time_limit); time_limit := time_limit + 60*long_t
  3254.     {$E OS_TIMER+} {$B OS_TIMER-}
  3255.     time_limit := counts_per_second*long_t
  3256.     {$E OS_TIMER-}
  3257.   end {set_timer};
  3258.  
  3259. function timeout {: boolean};        {added 26 Apr 89, RTC}
  3260.   
  3261.   {$B OS_TIMER+}
  3262.   var this_time : time_value;
  3263.   {$E OS_TIMER+}
  3264.   
  3265.   begin {timeout}
  3266.     {$B OS_TIMER+}
  3267.     long_time(this_time);
  3268.     timeout := this_time > time_limit
  3269.     {$E OS_TIMER+} {$B OS_TIMER-}
  3270.     time_limit := time_limit - 1;
  3271.     timeout := time_limit <= 0
  3272.     {$E OS_TIMER-}
  3273.   end {timeout};
  3274.  
  3275. procedure utl_version;
  3276.  
  3277. begin
  3278.    write(my_version);
  3279.   {$B OS_TIMER+}
  3280.   write(' (with TIMER)');
  3281.   {$E OS_TIMER+}
  3282.   writeln
  3283. end {utl_version};
  3284.  
  3285.  
  3286. begin { body of unit kermutil }
  3287.    { initialization code }
  3288.    old_flush := syscom^.crtinfo.flush;
  3289.    old_stop := syscom^.crtinfo.stop;
  3290.    syscom^.crtinfo.flush := chr(255);  { effectively turning flush off }
  3291.    syscom^.crtinfo.stop := chr(254);   { effectively turning stop off }
  3292.  
  3293.    ***;
  3294.  
  3295.    { termination code }
  3296.    syscom^.crtinfo.flush := old_flush;  { turn flush back on }
  3297.    syscom^.crtinfo.stop := old_stop     { turn stop back on }
  3298. end. { kermutil }
  3299. {>>>> SETSHOW.TEXT}
  3300.  
  3301. { Change log:
  3302. 30 Apr 89, V1.1: moved into kermutil   RTC
  3303. 30 Apr 89, V1.1: Added SET INTERFACE command    RTC
  3304. 16 Apr 89, V1.1: Added Client Unit to SHOW VER command      RTC
  3305. 14 Apr 89, V1.1: Added SHOW VERSION command   RTC
  3306. 14 Aug 88: Added SYSTEM-ID and modified DEBUG      RTC
  3307. 31 Jul 88: Modified to permit REMUNIT to accept/reject baud rate    RTC
  3308.  
  3309. }
  3310.  
  3311. procedure fill_parity_array;
  3312.  
  3313. (* parity value table for even parity...not(entry) = odd parity *)
  3314.  
  3315. const min = 0;
  3316.       max = 255;
  3317.  
  3318. var i, shifter, counter: integer;
  3319.     ch: char;
  3320.  
  3321. begin
  3322.    for ch := chr(min) to chr(max) do
  3323.      case parity of
  3324.         evenpar: begin
  3325.                     shifter := aand(ord(ch),255); (* mask off parity bit *)
  3326.                     counter := 0;
  3327.                     for i := 1 to 7 do begin       (* count the 1's *)
  3328.                        if odd(shifter) then
  3329.                           counter := counter + 1;
  3330.                        shifter := shifter div 2
  3331.                     end; (* for i *)
  3332.                     if odd(counter) then       (* stick a 1 on if necessary *)
  3333.                        parity_array[ch] := chr(aor(ord(ch),128))
  3334.                     else
  3335.                        parity_array[ch] := chr(aand(ord(ch),127))
  3336.                  end; (* for ch *) (* case even *)
  3337.         oddpar:  begin
  3338.                     shifter := aand(ord(ch),255);  (* mask off parity bit *)
  3339.                     counter := 0;
  3340.                     for i := 1 to 7 do begin        (* count the 1's *)
  3341.                        if odd(shifter) then
  3342.                            counter := counter + 1;
  3343.                        shifter := shifter div 2
  3344.                     end; (* for i *)
  3345.                     if odd(counter) then        (* stick a 1 on if necessary *)
  3346.                        parity_array[ch] := chr(aand(ord(ch),127))
  3347.                     else
  3348.                        parity_array[ch] := chr(aor(ord(ch),128))
  3349.                  end; (* for ch *) (* case odd *)
  3350.         markpar: parity_array[ch] := chr(aor(ord(ch),128));
  3351.         spacepar:parity_array[ch] := chr(aand(ord(ch),127));
  3352.         nopar:   parity_array[ch] := ch;
  3353.       end; (* case *)
  3354.   end; (* fill_parity_array *)
  3355.  
  3356. procedure write_bool{s: string255; b: boolean};
  3357.  
  3358. (* writes message & 'on' if b, 'off' if not b *)
  3359.   begin
  3360.     write(s);
  3361.     case b of
  3362.         true: writeln('on');
  3363.         false: writeln('off');
  3364.       end; (* case *)
  3365.   end; (* write_bool *)
  3366.  
  3367. procedure show_parms;
  3368.  
  3369. (* shows the various settable parameters *)
  3370. var
  3371.   i,first,last : vocab;
  3372.  
  3373. begin
  3374.    if noun = allsym then
  3375.      begin
  3376.        first := baudsym; last := systemsym
  3377.      end
  3378.    else
  3379.      begin
  3380.        first := noun; last := noun
  3381.      end;
  3382.    for i := first to last do
  3383.      case i of
  3384.        debugsym:    write_bool('Debugging is ',debug);
  3385.  
  3386.        escsym:      writeln('Escape character is ^',ctl(esc_char));
  3387.  
  3388.        filenamsym:  begin
  3389.                       write('File names are ');
  3390.                       if lit_names
  3391.                         then write('Literal')
  3392.                         else write('Converted');
  3393.                       writeln
  3394.                     end;
  3395.        
  3396.        filetypesym: begin
  3397.                       write('File type is ');
  3398.                       if f_is_binary
  3399.                         then write('Binary')
  3400.                         else write('Text');
  3401.                       writeln
  3402.                     end;
  3403.        
  3404.        filewarnsym: write_bool('File warning is ',fwarn);
  3405.  
  3406.        ibmsym:      write_bool('IBM is ',ibm);
  3407.  
  3408.        localsym:    write_bool('Local echo is ',halfduplex);
  3409.  
  3410.        emulatesym:  write_bool('Emulate DataMedia is ', emulating );
  3411.  
  3412.        baudsym:     writeln( 'Baud rate is ', baud:5 );
  3413.  
  3414.        paritysym:   begin
  3415.                        case parity of
  3416.                           evenpar: write('Even');
  3417.                           markpar: write('Mark');
  3418.                           nopar: write('No');
  3419.                           oddpar: write('Odd');
  3420.                           spacepar: write('Space');
  3421.                        end; (* case *)
  3422.                        writeln(' parity');
  3423.                     end; (* paritysym *)
  3424.      
  3425.        systemsym:   writeln('System ID is ',system_id);
  3426.        
  3427.      end; (* case *)
  3428.    if noun = versionsym then
  3429.      begin
  3430.        writeln(ker_version);
  3431.        rec_version; sen_version; cli_version;
  3432.        hlp_version; pak_version; utl_version; gbl_version;
  3433.        mnu_version; par_version;
  3434.      end
  3435. end; (* show_sym *)
  3436.  
  3437.  
  3438. procedure set_parms;
  3439.  
  3440. (* sets the parameters *)
  3441.   
  3442.   var
  3443.     oldbaud : integer;
  3444.  
  3445.   begin
  3446.     case noun of
  3447.         debugsym: debug := adj = onsym;
  3448.         escsym: escchar := newescchar;
  3449.         filenamsym : lit_names := adj = litsym;
  3450.         filetypesym : f_is_binary := adj = binsym;
  3451.         filewarnsym: fwarn := (adj = onsym);
  3452.         ibmsym: case adj of
  3453.                     onsym: begin
  3454.                         ibm := true;
  3455.                         parity := markpar;
  3456.                         half_duplex := true;
  3457.                         fillparityarray
  3458.                       end; (* onsym *)
  3459.                     offsym: begin
  3460.                         ibm := false;
  3461.                         parity := nopar;
  3462.                         half_duplex := false;
  3463.                         fillparityarray
  3464.                       end; (* onsym *)
  3465.                   end; (* case adj *)
  3466.         intsym: if adj = ucsdsym then menu_interface;
  3467.         localsym: halfduplex := (adj = onsym);
  3468.         emulatesym: emulating := (adj = onsym);
  3469.         paritysym: begin
  3470.               case adj of
  3471.                   evensym: parity := evenpar;
  3472.                   marksym: parity := markpar;
  3473.                   nonesym: parity := nopar;
  3474.                   oddsym: parity := oddpar;
  3475.                   spacesym: parity := spacepar;
  3476.                 end; (* case *)
  3477.               fill_parity_array;
  3478.              end; (* paritysym *)
  3479.         baudsym: begin
  3480.             oldbaud := baud; baud := newbaud;
  3481.             if not setup_comm then baud := oldbaud
  3482.          end { baudsym };
  3483.         systemsym: system_id := line;
  3484.       end; (* case *)
  3485.   end; (* set_parms *)
  3486. {>>>> KERMENUS.TEXT}
  3487. unit kermenus;
  3488.  
  3489. interface
  3490.   
  3491.   {Change log:
  3492.   14 May 89, V1.1: Added Parameters menu   RTC
  3493.   02 May 89, V1.1: Added menu to control log files   RTC
  3494.   30 Apr 89, V1.1: Originally written   RTC
  3495.   }
  3496.   
  3497.   procedure menu_interface;
  3498.   
  3499.   procedure mnu_version;
  3500.   
  3501. implementation
  3502.  
  3503.   uses screenops,
  3504.        {$U kermglob.code} kermglob,
  3505.        {$U kermutil.code} kermutil,
  3506.        {$U sender.code}   sender,
  3507.        {$U receiver.code} receiver,
  3508.        {$U client.code}   client;
  3509.   
  3510.   const
  3511.     my_version = '   Kermenus Unit V1.1, 14 May 89';
  3512.  
  3513.   procedure transfer_files;
  3514.     
  3515.     var
  3516.       ch : char;
  3517.     
  3518.     begin {transfer_files}
  3519.       ch := SC_prompt(concat('Kermit-UCSD File Transfer: ',
  3520.                              'S(end, R(eceive, G(et, P(ut, A(bort'),
  3521.                       -1,-1,0,menu_line,
  3522.                       ['S','R','G','P','A',' '],
  3523.                       false,',');
  3524.       SC_clr_line(menu_line);
  3525.       case ch of
  3526.         'G', 'R' : begin
  3527.                 if ch = 'G' then
  3528.                   begin
  3529.                     gotoxy(file_pos,file_line);
  3530.                     readln(xfilename); uppercase(xfilename)
  3531.                   end;
  3532.                 recsw(rec_ok,ch = 'G');
  3533.                 gotoxy(0,debugline);
  3534.                 write(chr(bell));
  3535.                 if rec_ok then
  3536.                     writeln('successful receive')
  3537.                 else
  3538.                     writeln('unsuccessful receive');
  3539.                 (*$I-*) (* set i/o checking off *)
  3540.                 if f_is_binary
  3541.                   then close(b_file)
  3542.                   else close(t_file);
  3543.                 (*$I+*) (* set i/o checking back on *)
  3544.               end; (* recsym *)
  3545.         'P', 'S' : begin
  3546.                 gotoxy(file_pos,file_line);
  3547.                 readln(xfilename); uppercase(xfilename);
  3548.                 sendsw(send_ok);
  3549.                 gotoxy(0,debugline);
  3550.                 write(chr(bell));
  3551.                 if send_ok then
  3552.                     writeln('successful send')
  3553.                 else
  3554.                     writeln('unsuccessful send');
  3555.                 (*$I-*) (* set i/o checking off *)
  3556.                 if f_is_binary
  3557.                   then close(b_file)
  3558.                   else close(t_file);
  3559.                 (*$I+*) (* set i/o checking back on *)
  3560.               end; (* sendsym *)
  3561.         'A', ' ' : begin
  3562.                 gotoxy(0,debugline);
  3563.                 write('file transfer aborted');
  3564.               end; {abort transfer}
  3565.       end {case ch}
  3566.     end {transfer_files};
  3567.     
  3568.   procedure logs;
  3569.     
  3570.     var
  3571.       ch_cmd,ch_log : char;
  3572.       log_message : string;
  3573.     
  3574.     begin {logs}
  3575.       ch_cmd := SC_prompt(concat('Kermit-UCSD Logs: ',
  3576.                              'O(pen, C(lose, A(bort'),
  3577.                       -1,-1,0,menu_line,
  3578.                       ['O','C','A',' '],
  3579.                       false,',');
  3580.       case ch_cmd of
  3581.         'O' : log_message := 'Open';
  3582.         'C' : log_message := 'Close';
  3583.         'A',' ' : exit(logs)
  3584.       end {case ch_cmd};
  3585.       ch_log := SC_prompt(concat('Kermit-UCSD ',log_message,' Log: ',
  3586.                              'D(ebug, A(bort'),
  3587.                       -1,-1,0,menu_line,
  3588.                       ['D','A',' '],
  3589.                       false,',');
  3590.       case ch_log of
  3591.         'D' : log_message := concat(log_message,' for Debug');
  3592.         'A',' ' : exit(logs)
  3593.       end {case ch_log};
  3594.       if ch_cmd = 'O' then {command was to open log}
  3595.         begin
  3596.           SC_clr_line(menu_line);
  3597.           write('File to ',log_message,' Logging>');
  3598.           readln(xfilename); uppercase(xfilename);
  3599.           {$I-}
  3600.           case ch_log of
  3601.             'D' :
  3602.               begin
  3603.                 close(debf,lock);
  3604.                 rewrite(debf,xfilename)
  3605.               end;
  3606.           end {case ch_log};
  3607.           if ioresult <> 0 then
  3608.             begin
  3609.               writeln('Unable to open ',xfilename);
  3610.               case ch_log of
  3611.                 'D' :
  3612.                   begin
  3613.                     close(debf);
  3614.                     rewrite(debf,'CONSOLE:')
  3615.                   end;
  3616.               end {case ch_log};
  3617.             end
  3618.           else {$I+}
  3619.             case ch_log of
  3620.               'D' : write(debf,
  3621.                   ker_version,' -- Debug log...');
  3622.             end
  3623.         end
  3624.       else {command was to close log}
  3625.         begin
  3626.           {$I-}
  3627.           case ch_log of
  3628.             'D' : close(debf,lock);
  3629.           end {case ch_log};
  3630.           if ioresult <> 0 then
  3631.             begin
  3632.               writeln('Unable to close file');
  3633.             end;
  3634.           case ch_log of
  3635.             'D' : rewrite(debf,'CONSOLE:');
  3636.           end {case ch_log};
  3637.           {$I+}
  3638.         end;
  3639.     end {logs};
  3640.   
  3641.   procedure menu_interface;
  3642.     
  3643.     var
  3644.       done : boolean;
  3645.       ch : char;
  3646.     
  3647.     procedure write_bool(b: boolean);
  3648.       
  3649.       {writes 'True' or 'False'}
  3650.       
  3651.       begin {write_bool}
  3652.         if b
  3653.           then write('True ')
  3654.           else write('False')
  3655.       end {write_bool};
  3656.     
  3657.     procedure read_bool(var b: boolean);
  3658.       
  3659.       var ch : char;
  3660.       
  3661.       begin {read_bool}
  3662.         SC_getc_ch(ch,['T','F']);
  3663.         b := ch = 'T'
  3664.       end {read_bool};
  3665.     
  3666.     procedure parameters;
  3667.       
  3668.       const
  3669.         name_line = 9;
  3670.         type_line = 10;
  3671.         warn_line = 11;
  3672.         baud_line = 12;
  3673.         parity_line = 13;
  3674.         echo_line = 14;
  3675.         ibm_line = 15;
  3676.         em_line = 16;
  3677.         esc_line = 17;
  3678.         debug_line = 18;
  3679.         sys_line = 19;
  3680.         opt_pos = 4;
  3681.         val_pos = 25;
  3682.       
  3683.       begin {parameters}
  3684.         SC_eras_eos(0,pred(name_line));
  3685.         repeat
  3686.           gotoxy(opt_pos,name_line); write('File N(ames'); 
  3687.           gotoxy(val_pos,name_line);
  3688.           if lit_names
  3689.             then write('Literal  ')
  3690.             else write('Converted');
  3691.           gotoxy(opt_pos,type_line); write('File T(ype'); 
  3692.           gotoxy(val_pos,type_line);
  3693.           if f_is_binary
  3694.             then write('Binary')
  3695.             else write('Text  ');
  3696.           gotoxy(opt_pos,warn_line); write('File W(arning'); 
  3697.           gotoxy(val_pos,warn_line); write_bool(f_warn);
  3698.           gotoxy(opt_pos,baud_line); write('B(aud rate'); 
  3699.           gotoxy(val_pos,baud_line); write(baud);
  3700.           gotoxy(opt_pos,parity_line); write('P(arity'); 
  3701.           gotoxy(val_pos,parity_line);
  3702.           case parity of
  3703.             evenpar: write('Even');
  3704.             markpar: write('Mark');
  3705.             nopar: write('None');
  3706.             oddpar: write('Odd');
  3707.             spacepar: write('Space');
  3708.           end {case parity};
  3709.           gotoxy(opt_pos,echo_line); write('L(ocal echo'); 
  3710.           gotoxy(val_pos,echo_line); write_bool(half_duplex);
  3711.           gotoxy(opt_pos,ibm_line); write('I(BM mode'); 
  3712.           gotoxy(val_pos,ibm_line); write_bool(ibm);
  3713.           gotoxy(opt_pos,em_line); write('eM(ulate Datamedia'); 
  3714.           gotoxy(val_pos,em_line); write_bool(emulating);
  3715.           gotoxy(opt_pos,esc_line); write('E(scape Character'); 
  3716.           gotoxy(val_pos,esc_line); write('^',ctl(esc_char));
  3717.           gotoxy(opt_pos,debug_line); write('D(ebugging'); 
  3718.           gotoxy(val_pos,debug_line); write_bool(debug);
  3719.           gotoxy(opt_pos,sys_line); write('S(ystem ID'); 
  3720.           gotoxy(val_pos,sys_line); write(system_id);
  3721.           ch := SC_prompt(concat('Kermit Parameters: {options} ',
  3722.                                '<space> to leave, ',
  3723.                                'switch to K(ermit style interface, V(ersion'),
  3724.                           -1,-1,0,menu_line,
  3725.                 ['D','E','N','T','W','I','L','M','B','P','S','K','V',' '],
  3726.                           false,',');
  3727.           case ch of
  3728.             'D' : begin
  3729.                     SC_erase_to_EOL(val_pos,debug_line); read_bool(debug)
  3730.                   end;
  3731.             'E' : repeat
  3732.                     SC_erase_to_EOL(val_pos,esc_line); 
  3733.                     read(keyboard,esc_char)
  3734.                   until esc_char in [chr(0)..chr(31)];
  3735.             'N' : begin
  3736.                     SC_erase_to_EOL(val_pos,name_line);
  3737.                     SC_getc_ch(ch,['L','C']);
  3738.                     lit_names := ch = 'L'
  3739.                   end;
  3740.             'T' : begin
  3741.                     SC_erase_to_EOL(val_pos,type_line);
  3742.                     SC_getc_ch(ch,['B','T']);
  3743.                     f_is_binary := ch = 'B'
  3744.                   end;
  3745.             'W' : begin
  3746.                     SC_erase_to_EOL(val_pos,warn_line); read_bool(f_warn)
  3747.                   end;
  3748.             'I' : begin
  3749.                     SC_erase_to_EOL(val_pos,ibm_line); read_bool(ibm);
  3750.                     if ibm then
  3751.                       begin
  3752.                         parity := markpar;
  3753.                         half_duplex := true
  3754.                       end
  3755.                     else
  3756.                       begin
  3757.                         parity := nopar;
  3758.                         half_duplex := false
  3759.                       end;
  3760.                     fill_parity_array
  3761.                   end;
  3762.             'L' : begin
  3763.                     SC_erase_to_EOL(val_pos,echo_line); read_bool(halfduplex)
  3764.                   end;
  3765.             'M' : begin
  3766.                     SC_erase_to_EOL(val_pos,em_line); read_bool(emulating)
  3767.                   end;
  3768.             'B' : repeat
  3769.                     SC_erase_to_EOL(val_pos,baud_line); {$I-} read(baud); {$I+}
  3770.                     SC_erase_to_EOL(0,menu_line)
  3771.                   until setup_comm;
  3772.             'P' : begin
  3773.                     SC_erase_to_EOL(val_pos,parity_line); 
  3774.                     SC_getc_ch(ch,['E','O','M','S','N']);
  3775.                     case ch of
  3776.                       'E' : parity := evenpar;
  3777.                       'M' : parity := markpar;
  3778.                       'N' : parity := nopar;
  3779.                       'O' : parity := oddpar;
  3780.                       'S' : parity := spacepar;
  3781.                     end {case ch};
  3782.                     fill_parity_array
  3783.                   end;
  3784.             'S' : begin
  3785.                     SC_erase_to_EOL(val_pos,sys_line); readln(system_id)
  3786.                   end;
  3787.             'K' : begin
  3788.                     done := true; {switch back to KERMIT style interface}
  3789.                     SC_clr_screen; exit(parameters)
  3790.                   end;
  3791.             'V' : begin
  3792.                     SC_eras_eos(0,name_line);
  3793.                     noun := versionsym; show_parms;
  3794.                     exit(parameters)
  3795.                   end;
  3796.             ' ' : exit(parameters);
  3797.           end {case ch}
  3798.         until false
  3799.       end {parameters};
  3800.     
  3801.     begin {menu_interface}
  3802.       done := false;
  3803.       writescreen('');
  3804.       repeat
  3805.         ch := SC_prompt(concat('Kermit-UCSD: ',
  3806.                                'C(onnect, T(ransfer Files, Q(uit, ',
  3807.                                'S(et Parameters, L(ogs, B(ye, F(inish'),
  3808.                         -1,-1,0,menu_line,
  3809.                         ['C','T','Q','S','L','B','F'],
  3810.                         false,',');
  3811.         SC_clr_line(status_line); SC_clr_line(debug_line);
  3812.         case ch of
  3813.           'C' : begin SC_clr_screen; connect; writescreen('') end;
  3814.           'T' : transfer_files;
  3815.           'L' : logs;
  3816.           'F', 'B' : begin
  3817.                   case ch of
  3818.                     'F' : line := 'F';
  3819.                     'B' : line := 'L';
  3820.                   end {case};
  3821.                   clientsw(send_ok,'G',line);
  3822.                   gotoxy(0,debugline);
  3823.                   write(chr(bell));
  3824.                   if send_ok then
  3825.                       writeln('successful transaction')
  3826.                   else
  3827.                       writeln('unsuccessful transaction');
  3828.                   (*$I-*) (* set i/o checking off *)
  3829.                   close(t_file);
  3830.                   (*$I+*) (* set i/o checking back on *)
  3831.                 end; {generic server command}
  3832.           'S' : parameters;
  3833.           'Q' : begin done := true; verb := quitsym end;
  3834.         end {case ch}
  3835.       until done
  3836.     end {menu_interface};
  3837.   
  3838.   procedure mnu_version;
  3839.     
  3840.     begin {mnu_version}
  3841.       writeln(my_version)
  3842.     end {mnu_version};
  3843.   
  3844. end {kermenus}.
  3845. {>>>> KERMPACK.TEXT}
  3846. unit kermpack;
  3847.  
  3848. interface
  3849.  
  3850.    uses {$U kermglob.code} kermglob;
  3851.  
  3852. {Change log:
  3853. 30 Apr 89, V1.1: Eliminated "no timeout on receive" checks   RTC
  3854. 26 Apr 89, V1.1: Changed to "timer" controlled timeouts   RTC
  3855. 19 Apr 89, V1.1: minor cleanups   RTC
  3856. 13 Apr 89, V1.1: Added Version message        RTC
  3857. 14 Aug 88: Fixed packetwrite to output to debf          RTC
  3858. 31 Jul 88: Modified for exact size binary xfr, misc. cleanup    RTC
  3859. 02 Jul 88: Added binary transfers        RTC
  3860.  
  3861. }
  3862.  
  3863.    procedure spar(var packet: packettype);
  3864.  
  3865.    procedure rpar(var packet: packettype; len : integer);
  3866.  
  3867.    procedure spack(ptype: char; num:integer; len: integer; data: packettype);
  3868.  
  3869.    function rpack(var len, num: integer; var data: packettype): char;
  3870.  
  3871.    procedure bufemp(buffer: packettype; len: integer);
  3872.  
  3873.    function bufill(var buffer: packettype): integer;
  3874.    
  3875.    procedure pak_version;
  3876.  
  3877.  
  3878. implementation
  3879.  
  3880. uses {$U kermutil.code} kermutil;
  3881.  
  3882. const
  3883.   my_version = '   Kermpack Unit V1.1, 30 Apr 89';
  3884.  
  3885.  
  3886. procedure bufemp(*buffer: packettype; var f: text; len: integer*);
  3887.  
  3888. (* empties a packet into a file *)
  3889. { Note: this strips out ALL linefeed characters! }
  3890.  
  3891. var i,ls: integer;
  3892.     r: char;
  3893.     set_bit_8 : boolean;
  3894.     s: string255;
  3895.  
  3896. procedure write_bin;
  3897.  
  3898.   var
  3899.     dummy : integer;
  3900.   
  3901.   begin {write_bin}
  3902.     filebuf[bufpos] := r;
  3903.     i := succ(i); bufpos := succ(bufpos);
  3904.     if bufpos > blksize then
  3905.       begin
  3906.         {$I-}
  3907.         dummy := blockwrite(b_file,filebuf,1);
  3908.         if io_result <> 0 then
  3909.           begin
  3910.             io_error(ioresult);         {tell them and...}
  3911.             currstate := 'a'            {abort}
  3912.           end;
  3913.         {$I+}
  3914.         bufpos := 1
  3915.       end
  3916.   end {write_bin};
  3917.  
  3918. procedure write_text;
  3919.  
  3920.   var
  3921.     dummy : integer;
  3922.   
  3923.   begin {write_text}
  3924.       if ord(r) = lf then { skip linefeeds SP }
  3925.          i := i + 1
  3926.       else if (ord(r) = cr) then begin     (* else if a carriage return then *)
  3927.          i := i + 1;
  3928.          (*$I-*)                           (* turn i/o checking off *)
  3929.          writeln(t_file,s);                (* and write out line to file *)
  3930.          s := copy('',0,0);                (* empty the string var *)
  3931.          ls := 0;
  3932.          (*$I+*)                           (* turn i/o checking back on *)
  3933.       end
  3934.       else begin                           (* else, is a regular char, so Q5R      $H     s := concat(s,' ');               (* and add character to out string *)
  3935.         ls := ls + 1;
  3936.          s[ls] := r;
  3937.          if length(s) >= 255 then          {dump full string  RTC}
  3938.            begin
  3939.              {$I-}
  3940.              write(t_file,s);
  3941.              s := ''; ls := 0
  3942.              {$I+}
  3943.            end;
  3944.          i := i + 1                (* increase buffer pointer *)
  3945.       end; (* else *)
  3946.       if (io_result <> 0) then begin (* if io_error *)
  3947.          io_error(ioresult);     (* tell them and *)
  3948.          currstate := 'a';           (* abort *)
  3949.       end (* if *)
  3950.   end {write_text};
  3951.  
  3952. begin
  3953.    s := copy('',0,0);
  3954.    ls := 0;
  3955.    i := 0;
  3956.    while i < len do begin
  3957.       r := buffer[i];          (* get a character *)
  3958.       if en_qbin and (r = qbin) then
  3959.         begin
  3960.           i := succ(i);
  3961.           r := buffer[i];      {get 8 bit quoted char}
  3962.           set_bit_8 := true
  3963.         end
  3964.       else set_bit_8 := false;
  3965.       if (r = myquote) then begin   (* if character is control quote *)
  3966.          i := i + 1;                (* skip over quote and *)
  3967.          r := buffer[i];            (* get quoted character *)
  3968.          if not (chr(aand(ord(r),127)) in 
  3969.                  ctl_set - [chr(0)..chr(31),chr(del)]) then
  3970.             r := ctl(r);    (* controllify it *)
  3971.       end; (* if *)
  3972.       if set_bit_8 then r := chr(aor(ord(r),128));
  3973.       if f_is_binary
  3974.         then write_bin
  3975.         else write_text
  3976.    end; (* while *)                     (* and get another char *)
  3977.    if not f_is_binary then
  3978.      begin
  3979.        (*$I-*)                          (* turn i/o checking off *)
  3980.        write(t_file,s);                 (* and write out line to file *)
  3981.        if (io_result <> 0) then begin   (* if io_error *)
  3982.           io_error(ioresult);           (* tell them and *)
  3983.           currstate := 'a';             (* abort *)
  3984.        end (* if *)
  3985.        (*$I+*)                          (* turn i/o checking back on *)
  3986.      end
  3987. end; (* bufemp *)
  3988.  
  3989.  
  3990. function bufill(*var buffer: packettype): integer*);
  3991.  
  3992. (* fill a packet with data from a file *)
  3993.  
  3994. var i : integer;
  3995.     r : char;
  3996.  
  3997.   function done : boolean;
  3998.     
  3999.     begin {done}
  4000.       if f_is_binary
  4001.         then done := (bufpos > last_blksize) and eof(b_file)
  4002.         else done := eof(t_file)
  4003.     end {done};
  4004.  
  4005.   begin
  4006.     i := 0;
  4007.     (* while file has some data & packet has some room we'll keep going *)
  4008.     while not done and (i < spsiz-9) do
  4009.       begin
  4010.         if f_is_binary then
  4011.           begin
  4012.             (* if we need more data from disk then *)
  4013.             if (bufpos > bufend) and (not eof(b_file)) then
  4014.               begin
  4015.                 {$I-}
  4016.                 bufend := blockread(b_file,filebuf[1],1) * blksize;
  4017.                 if io_result <> 0 then
  4018.                   begin
  4019.                     bufill := at_badblk;
  4020.                     exit(bufill)
  4021.                   end;
  4022.                 {$I+}
  4023.                 (* and adjust buffer pointer *)
  4024.                 bufpos := 1
  4025.               end; (* if *)
  4026.             r := filebuf[bufpos];      (* get a character *)
  4027.             bufpos := bufpos + 1;         (* increase buffer pointer *)
  4028.           end
  4029.         else
  4030.           begin
  4031.             r := t_file^;
  4032.             {$I-}
  4033.             if eoln(t_file) then
  4034.               begin
  4035.                 buffer[i] := quote;      (* put (quoted) CR in buffer *)
  4036.                 i := i + 1;
  4037.                 buffer[i] := ctl(chr(cr));
  4038.                 i := i + 1;
  4039.                 r := chr(lf);            (* and we'll stick a LF after *)
  4040.               end;
  4041.             get(t_file);
  4042.             if io_result <> 0 then
  4043.               begin
  4044.                 bufill := at_badblk;
  4045.                 exit(bufill)
  4046.               end
  4047.             {$I+}
  4048.           end;
  4049.         if en_qbin and (ord(r) > 127) then
  4050.           begin
  4051.             r := chr(ord(r)-128);       {remove the 8th bit}
  4052.             buffer[i] := qbin;          {insert prefix}
  4053.             i := succ(i)
  4054.           end;
  4055.         if chr(aand(ord(r),127)) in ctl_set then     (* if a control char *)
  4056.           begin
  4057.             buffer[i] := quote;      (* put the quote in buffer *)
  4058.             i := i + 1;
  4059.             if not (chr(aand(ord(r),127)) in
  4060.                     ctl_set - [chr(0)..chr(31),chr(del)]) then
  4061.                 r := ctl(r);   (* and un-controllify char *)
  4062.           end (* if *);
  4063.         buffer[i] := r;
  4064.         i := i + 1;
  4065.       end; (* while *)
  4066.     if (i = 0) then                         (* if we're at end of file, *)
  4067.         bufill := at_eof                    (* indicate it *)
  4068.     else                                    (* else *)
  4069.         bufill := i                         (* return # of chars in packet *)
  4070.   end; (* bufill *)
  4071.  
  4072.  
  4073. procedure spar(*var packet: packettype*);
  4074.  
  4075. (* fills data array with my send-init parameters *)
  4076.  
  4077.   begin
  4078.     packet[0] := tochar(chr(maxpack+1));   (* biggest packet i can receive *)
  4079.     packet[1] := tochar(chr(mytime));    (* when i want to be timed out *)
  4080.     packet[2] := tochar(chr(mypad));     (* how much padding i need *)
  4081.     packet[3] := ctl(chr(mypchar));      (* padding char i want *)
  4082.     packet[4] := tochar(chr(myeol));     (* end of line character i want *)
  4083.     packet[5] := myquote;                (* control-quote char i want *)
  4084.     if parity = nopar
  4085.       then packet[6] := 'Y'              (* I will do 8-bit quoting *)
  4086.       else packet[6] := my_qbin;         { I need to do 8-bit quoting }
  4087.     packet[7] := '1';                    { checksum type I want }
  4088.     packet[8] := 'N';                    { I will not do run len encoding }
  4089.     packet[9] := tochar(chr(8));         { I can do attributes packets }
  4090.     debugwrite('spar:')
  4091.   end; (* spar *)
  4092.  
  4093. procedure rpar(*var packet: packettype; len : integer*);
  4094.  
  4095. (* gets their init params *)
  4096.  
  4097.   begin
  4098.     if len > 0
  4099.       then spsiz := ord(unchar(packet[0]))     (* max send packet size *)
  4100.       else spsiz := 80;
  4101.     if len > 1
  4102.       then timint := ord(unchar(packet[1]))    (* when i should time out *)
  4103.       else timint := my_time;
  4104.     if len > 2
  4105.       then pad := ord(unchar(packet[2]))       (* number of pads to send *)
  4106.       else pad := 0;
  4107.     if len > 3
  4108.       then padchar := ctl(packet[3])           (* padding char to send *)
  4109.       else padchar := chr(my_pchar);
  4110.     if len > 4
  4111.       then xeol := unchar(packet[4])           (* eol char i must send *)
  4112.       else xeol := chr(my_eol);
  4113.     if len > 5
  4114.       then quote := packet[5]                  (* incoming data quote char *)
  4115.       else quote := my_quote;
  4116.     if len > 6
  4117.       then qbin := packet[6]                   { incoming 8th bit quote }
  4118.       else qbin := 'N';
  4119.     if parity = nopar
  4120.       then en_qbin := qbin in [chr(33)..chr(62),chr(96)..chr(126)]
  4121.       else
  4122.         begin
  4123.           if q_bin = 'Y' then qbin := my_qbin;
  4124.           en_qbin := qbin = my_qbin
  4125.         end;
  4126.     if len > 9
  4127.       then en_attr := aand(ord(unchar(packet[9])),8) = 8
  4128.       else en_attr := false;
  4129.     debugwrite('rpar:')
  4130.   end; (* rpar *)
  4131.  
  4132. procedure packetwrite(p: packettype; len: integer);
  4133.  
  4134. (* writes out all of a packet for debugging purposes *)
  4135.  
  4136. var i: integer;
  4137.  
  4138.   begin
  4139.     gotoxy(0,debugline);
  4140.     for i := 0 to len-1 do
  4141.         write(debf,p[i])
  4142.   end; (* packetwrite *)
  4143.  
  4144. procedure spack(*ptype: char; num: integer; len: integer; data: packettype*);
  4145.  
  4146. (* send a packet *)
  4147.  
  4148. var i: integer;
  4149.     chksum: char;
  4150.     ch: char;
  4151.  
  4152.   begin
  4153.     debugwrite('spack:');
  4154.     if ibm and (currstate <> 's') then           (* if ibm and not SINIT then *)
  4155.       begin
  4156.         set_timer(timint);
  4157.         repeat                                 (* wait for an xon *)
  4158.             repeat
  4159.             until (readch(inport, ch)) or timeout;
  4160.         until (ch = xon) or timeout;
  4161.         if timeout then                 (* if wait too long then *)
  4162.           begin
  4163.             exit(spack)                          (* get out *)
  4164.           end; (* if *)
  4165.       end; (* if *)
  4166.  
  4167.     for i := 1 to pad do
  4168.         write_ch(oport,parity_array[padchar]);(* write out any padding chars *)
  4169.     write_ch(oport,parity_array[chr(soh)]);                (* packet sync character *)
  4170.     chksum := tochar(chr(len + 3));          (* init chksum *)
  4171.     write_ch(oport,parity_array[tochar(chr(len + 3))]);    (* character count *)
  4172.     chksum := chr(ord(chksum) + ord(tochar(chr(num))));
  4173.     write_ch(oport,parity_array[tochar(chr(num))]);
  4174.     chksum := chr(ord(chksum) + ord(ptype));
  4175.     write_ch(oport,parity_array[ptype]);                   (* packet type *)
  4176.  
  4177.     for i := 0 to len - 1 do                 (* loop through data chars *)
  4178.       begin
  4179.         write_ch(oport,parity_array[data[i]]);             (* store char *)
  4180.         chksum := chr(ord(chksum) + ord(data[i]))
  4181.       end; (* for i *)
  4182.                                              (* compute final chksum *)
  4183.     chksum := chr(aand(ord(chksum) + (aand(ord(chksum),192) div 64), 63));
  4184.     write_ch(oport,parity_array[tochar(chksum)]);
  4185.     write_ch(oport,parity_array[xeol]);
  4186.  
  4187.     if debug then
  4188.       begin
  4189.         write(debf,' len:',len,' num:',num,' ptype:',ptype);
  4190.         packetwrite(data,len); write(debf,' chksum:',tochar(chksum))
  4191.       end
  4192.   end; (* spack *)
  4193.  
  4194. (*$G+*) (* turn on goto option...need it for next routine *)
  4195.  
  4196. function rpack(*var len, num: integer; var data: packettype): char*);
  4197.  
  4198. (* read a packet *)
  4199.  
  4200. label 1; (* used to emulate C's CONTINUE statement *)
  4201.  
  4202. var i, ichksum: integer;
  4203.     chksum, ptype: char;
  4204.     r: char;
  4205.  
  4206.   begin
  4207.     debugwrite('rpack:');
  4208.     set_timer(timint);
  4209.  
  4210.     if not getsoh then                       (*if don't get synch char then *)
  4211.       begin
  4212.         rpack := 'N';                        (* treat as a NAK *)
  4213.         num := n mod 64;
  4214.         exit(rpack)                          (* and get out of here *)
  4215.       end;
  4216.  
  4217.   1: if timeout then                        (* if we've tried too many times *)
  4218.         begin                               (* and aren't waiting for init *)
  4219.           rpack := 'N';                      (* treat as NAK *)
  4220.           exit(rpack)                        (* and get out of here *)
  4221.         end; (* if *)
  4222.  
  4223.     if not getch(r) then                (* get a char and *)
  4224.             goto 1;                        (* resynch if soh *)
  4225.  
  4226.     ichksum := ord(r);                        (* start checksum *)
  4227.     len := ord(unchar(r)) - 3;          (* character count *)
  4228.  
  4229.     if not getch(r) then                (* get a char and *)
  4230.         goto 1;                            (* resynch if soh *)
  4231.     ichksum := ichksum + ord(r);
  4232.     num := ord(unchar(r));              (* packet number *)
  4233.  
  4234.     if not getch(r) then                (* get a char and *)
  4235.         goto 1;                            (* resynch if soh *)
  4236.     ichksum := ichksum + ord(r);
  4237.     ptype := r;                         (* packet type *)
  4238.  
  4239.     for i := 0 to len-1 do                 (* get any data *)
  4240.       begin
  4241.         if not getch(r) then            (* get a char and *)
  4242.             goto 1;                        (* resynch if soh *)
  4243.         ichksum := ichksum + ord(r);
  4244.         data[i] := r;
  4245.       end; (* for i *)
  4246.     data[len] := chr(0);                   (* mark end of data *)
  4247.  
  4248.     if not getch(r) then                (* get a char and *)
  4249.         goto 1;                            (* resynch if soh *)
  4250.  
  4251.                                            (* compute final checksum *)
  4252.     chksum := chr(aand(ichksum + (aand(ichksum,192) div 64), 63));
  4253.  
  4254.     if (chksum <> unchar(r)) then       (* if checksum bad *)
  4255.         rpack := chr(0)                      (* return 'false' indicator *)
  4256.     else                                   (* else *)
  4257.         rpack := ptype;                      (* return packet type *)
  4258.  
  4259.     if debug then
  4260.       begin
  4261.         write(debf,' len:',len,' num:',num,' ptype:',ptype);
  4262.         packetwrite(data,len); write(debf,' chksum:',r)
  4263.       end; (* if *)
  4264.   end; (* rpack *)
  4265.  
  4266. (*$G-*) (* turn off goto option...don't need it anymore *)
  4267.  
  4268. procedure pak_version;
  4269.   
  4270.   begin
  4271.     writeln(my_version)
  4272.   end {pak_version};
  4273.  
  4274. end. { kermpack }
  4275. {>>>> KERMGLOB.TEXT}
  4276. unit kermglob;
  4277.  
  4278. interface
  4279.     
  4280. {Change log:
  4281. 13 May 89, V1.1: Added COMMENT vocab. & Eliminated "int_bool_rec"   RTC
  4282. 30 Apr 89, V1.1: Added vocabulary for SET INTERFACE command   RTC
  4283. 26 Apr 89, V1.1: minor cleanups   RTC
  4284. 16 Apr 89, V1.1: Added BYE & FINISH commands       RTC
  4285. 13 Apr 89, V1.1: Added Version message      RTC
  4286. 14 Aug 88: Added LOG, CLOSE, and SET SYSTEM commands    RTC
  4287. 31 Jul 88: Added variable system_id string for REMUNIT    RTC
  4288. 31 Jul 88: Added attributes packets & exact size bin. xfrs    RTC
  4289. 10 Jul 88: Removed screen command definitions    RTC
  4290. 30 Jun 88: Modified for binary files, "take", ^X & ^Z   RTC
  4291. }
  4292.    
  4293.    const
  4294.          blksize = 512;
  4295.          oport = 8;          (* output port # *)
  4296.          inport = 7;
  4297.          keyport = 2;
  4298.          bell = 7;           (* ASCII bell *)
  4299.          maxpack = 93;       (* maximum packet size minus 1 *)
  4300.          soh = 1;            (* start of header *)
  4301.          sp = 32;            (* ASCII space *)
  4302.          cr = 13;            (* ASCII CR *)
  4303.          lf = 10;            (* ASCII line feed *)
  4304.          del = 127;          (* delete *)
  4305.          can_cur = 24;       { cancel current file char ^X }
  4306.          can_all = 26;       { cancel all files char    ^Z }
  4307.          my_esc = 29;        (* default esc char for connect (^]) *)
  4308.          maxtry = 5;         (* number of times to retry sending packet *)
  4309.          my_quote = '#';     (* quote character I'll use *)
  4310.          my_qbin = '&';      { 8th bit quote character I want }
  4311.          my_pad = 0;         (* number of padding chars I need *)
  4312.          my_pchar = 0;       (* padding character I need *)
  4313.          my_eol = 13;        (* end of line character i need *)
  4314.          my_time = 5;        (* seconds after which I should be timed out *)
  4315.          maxtim = 20;        (* maximum timeout interval *)
  4316.          mintim = 2;         (* minimum time out interval *)
  4317.          at_eof = -1;        (* value to return if at eof *)
  4318.          at_badblk = -2;     { value to return if at bad block }
  4319.          {rqsize = 5000;      (* input queue size *)
  4320.          qsize1 = 5001;      (* qsize + 1 *)}
  4321.          eoln_sym = 13;      (* pascal eoln sym *)
  4322.          back_space = 8;     (* pascal backspace sym *)
  4323.          defaultbaud = 1200; (* default baud rate *)
  4324.  
  4325.    (* screen control information *)
  4326.      (* console line on which to put specified info *)
  4327.          menu_line = 0;
  4328.          title_line = 2;
  4329.          statusline = 3;
  4330.          packet_line = 4;
  4331.          retry_line = 5;
  4332.          file_line = 6;
  4333.          error_line = 7;
  4334.          debug_line = 8;
  4335.          prompt_line = 9;
  4336.      (* position on line to put info *)
  4337.          statuspos = 60;
  4338.          packet_pos = 19;
  4339.          retry_pos = 17;
  4340.          file_pos = 11;
  4341.  
  4342.    type packettype = packed array[0..maxpack] of char;
  4343.         parity_type = (evenpar, oddpar, markpar, spacepar, nopar);
  4344.  
  4345.         string255 = string[255];
  4346.  
  4347.  
  4348.         statustype = (null, at_eol, unconfirmed, parm_expected, ambiguous,
  4349.                       unrec, fn_expected, ch_expected, num_expected);
  4350.         vocab = (nullsym, allsym, baudsym, binsym, byesym, closesym, comsym,
  4351.                  consym, convsym, debugsym, emulatesym, escsym, evensym,
  4352.                  exitsym, filenamsym, filetypesym, filewarnsym, finsym,
  4353.                  getsym, helpsym, ibmsym, intsym, kermitsym, litsym,
  4354.                  localsym, logsym, marksym, nonesym, oddsym, offsym, onsym,
  4355.                  paritysym, putsym, quitsym, recsym, sendsym, setsym,
  4356.                  showsym, spacesym, systemsym, takesym, textsym, ucsdsym,
  4357.                  versionsym);
  4358.  
  4359.     var noun, verb, adj: vocab;
  4360.         status: statustype;
  4361.         vocablist: array[vocab] of string[13];
  4362.         xfilename, line: string255;
  4363.         newescchar: char;
  4364.         expected: set of vocab;
  4365.         newbaud: integer;
  4366.  
  4367.         currstate: char; (* current state *)
  4368.         xeol, quote, qbin, esc_char: char;
  4369.         lit_names, f_is_binary, fwarn, ibm, half_duplex,
  4370.         en_attr, en_qbin, debug: boolean;
  4371.         i, size, rpsiz, spsiz, pad, n, num_try, oldtry, timint: integer;
  4372.         recpkt, packet: packettype;
  4373.         padchar, ch: char;
  4374.         s: string255;
  4375.         debf: text; (* file for debug output *)
  4376.         parity: parity_type;
  4377.         xon: char;
  4378.         filebuf: packed array[1..blksize] of char;
  4379.         bufpos, bufend: integer;
  4380.         parity_array: packed array[char] of char;
  4381.         ctlset: set of char;
  4382.         rec_ok, send_ok: boolean;
  4383.         baud: integer;
  4384.         emulating: boolean;
  4385.         last_blksize : integer;  {size of last block of boolean file}
  4386.         t_file : text   {file for text file transfers};
  4387.         b_file : file   {file for binary file transfers};
  4388.         cmd_file : text {file of "take" commands};
  4389.         ker_version,            { version id for other units }
  4390.         system_id : string      {id string for REMUNIT};
  4391.  
  4392.    procedure gbl_version;
  4393.  
  4394. implementation
  4395.    
  4396.    const
  4397.      my_version = '   Kermglob Unit V1.1, 13 May 89';
  4398.  
  4399.    procedure gbl_version;
  4400.      
  4401.      begin
  4402.        writeln(my_version)
  4403.      end {gbl_version};
  4404.  
  4405. end. { kermglob }
  4406. {>>>> UCPECAN.M.TEXT}
  4407. ckermglob
  4408.  
  4409.  
  4410. cfakeutil
  4411. kermutil
  4412.  
  4413. ckermpack
  4414.  
  4415.  
  4416. cparser
  4417.  
  4418.  
  4419. chelper
  4420.  
  4421.  
  4422. csender
  4423.  
  4424.  
  4425. creceiver
  4426.  
  4427.  
  4428. cclient
  4429.  
  4430.  
  4431. ckermenus
  4432.  
  4433.  
  4434. ckermutil
  4435.  
  4436.  
  4437. ckermit
  4438.  
  4439.  
  4440. {>>>>}
  4441.