
(* RECEIVE SECTION *)
UCSD Pascal KERMIT for the Terak p-System, from Kate MacGregor, Cornell U
Modified for the Magiscan 2 by H Balen, Lancaster U 

segment procedure recsw(var rec_ok: boolean);

function rdata: char;

(* send file data *)

var Blk, num, len: integer;
    ch: char;

  begin

    repeat
        if numtry > maxtry then
          begin
            debugwrite('too many intial retries in rdata');
            state := 'a';
            exit(rdata)
          end;

        num_try := num_try + 1;

        ch := rpack(len,num,recpkt);   (* receive a packet *)
        if debug and (ch<>chr(0)) then packetwrite(recpkt,len);

        refresh_screen(numtry,n);

        if (ch = 'D') then             (* got data packet *)
          begin
            if (num <> (n mod 64)) then (* wrong packet *)
              begin
                if (oldtry > maxtry) then
                  begin
                    debugwrite('too many data retries in rdata');
                    rdata := 'a';      (* too many tries, abort *)
                    exit(rdata)
                  end; (* if *)

                n := n - 1;

                if (num = (n mod 64)) then (* previous packet again *)
                  begin                (* so re-ACK it *)
                    debugint('re-acking ',num);
                    spack('Y',num,6,packet);
                    numtry := 0;       (* reset try counter *)
                                       (* stay in same state *)
                  end (* if *)
                else begin             (* wrong number *)
                    debugwrite('wrong data sequence no. in rdata');
                    state := 'a'       (* so abort *)
                    end
              end (* if *)
            else                       (* right packet *)
              begin
                if TranState = TxtFile then
                  bufemp(recpkt,f,len)  (* write data to file *)
                 else
                   Bbufemp(recpkt,len);
                spack('Y',(n mod 64),0,packet); (* ACK packet *)
                oldtry := numtry;      (* reset try counters *)
                if numtry > 1 then
                    if istbrr then     (* clear buffer *)
                      begin
                        ch:=rcvbbt;
                        ch:='D';
                      end;
                numtry := 0;
                n := n + 1             (* bump packet number *)
                                       (* stay in data send state *)
              end (* else *)
          end (* if 'D' *)
        else if (ch = 'F') then        (* file header *)
          begin
            if (oldtry > maxtry) then
              begin
                debugwrite('too many file head tries in rdata');
                rdata := 'a';          (* too many tries, abort *)
                exit(rdata)
              end; (* if *)

            n := n - 1;

            if (num = (n mod 64)) then (* previous packet again *)
              begin                    (* so re-ACK it *)
                debugint('re-acking file header ',num);
                spack('Y',num,0,packet);
                if istbrr then begin
                  ch:=rcvbbt; (* and empty out buffer *)
                  ch:='F';
                  end;
                numtry := 0;           (* reset try counter *)
                state := state;        (* stay in same state *)
              end (* if *)
            else begin
              debugwrite('file info not previous packet in rdata');
                state := 'a'           (* not previous packet, abort *)
                end
          end (* if 'F' *)
        else if (ch = 'Z') then        (* end of file *)
          begin
            if (num <> (n mod 64)) then(* wrong packet, abort *)
              begin
                debugwrite('wrong eof packet in rdata');
                rdata := 'a';
                exit(rdata)
              end; (* if *)
            spack('Y',n mod 64,0,packet); (* ok, ACK it *)
            { CloseF(filename,True); }
            n :=  n + 1;               (* bump packet counter *)
            state := 'b';              (* go to break state *)
            oldtry := numtry;
            numtry := 0;
          end (* else if 'Z' *)
        else if (ch = 'E') then        (* error packet *)
          begin
            error(recpkt,len);         (* display error *)
            state := 'a'               (* and abort *)
          end (* if 'E' *)
        else if (ch <> chr(0)) then begin (* some other packet type, *)
            state := 'a';                 (* abort *)
            debugwrite('wierd rdata packet');
            end
    until (state <> 'd');
    rdata := state
  end; (* rdata *)

function rfile: char;

(* receive file header *)

var num, len: integer;
    ch: char;
    oldfn: string;
    i: integer;

procedure makename(recpkt: packettype; var fn: string; l: integer);

function exist(fn: string): boolean;

(* returns true if file named fn exists *)

var f: file;
    OK : boolean;

  begin
    (*$I-*) (* turn off i/o checking *)
    reset(f,concat(disk,fn));
    OK := (ioresult = 0);
    if OK then
      close(f);
    Exist := OK
    (*$I+*)
  end; (* exist *)

procedure checkname(var fn: string);

(* if file fn exists, makes a new name which doesn't *)
(* does this by changing letters in file name until it *)
(* finds some combination which doesn't exitst *)

var ch: char;
    i: integer;

  begin
    i := 1;
    while (i <= length(fn)) and exist(fn) do
      begin
        ch := 'A';
        while (ch in ['A'..'Z']) and exist(fn) do
          begin
            fn[i] := ch;
            ch := succ(ch);
          end; (* while *)
        i := i + 1
      end; (* while *)
    end; (* checkname *)

  begin (* makename *)
    fn := copy('               ',1,15);    (* stretch length *)
    moveleft(recpkt[0],fn[1],l);           (* get filename from packet *)
    oldfn := copy(fn, 1,l);                (* save fn sent to show user *)
    fn := copy(fn,1,min(15,l));            (* set length of filename *)
                                           (* and make sure <= 15 *)
    uppercase(fn);
    {
    if length(fn) > 10 then
      fn := copy(fn,1,10);           (* can only be 15 long in all *)
    }
    if TranState = TxtFile then
      begin
      if pos('.TEXT',fn) <> (length(fn)-4) then
        begin
        if length(fn) > 10 then
          fn := copy(fn,1,10);           (* can only be 15 long in all *)
        fn := concat(fn,'.TEXT');          (* and we'll add .TEXT *)
        end; (* if *)
      end
     else
       if TranState = CodeFile then
         begin{ Same as above except this is a code file }
         if pos('.CODE',fn) <> (length(fn)-4) then
           begin
           if length(fn) > 10 then
             fn := copy(fn,1,10);
           fn := concat(fn,'.CODE')
           end
         end
        else
          begin { Same as last two but this is a data file }
          if pos('.DATA',fn) <> (length(fn)-4) then
            begin
            if length(fn) > 10 then
              fn := copy(fn,1,10);
            fn := concat(fn,'.DATA')
            end;
          end;
    if fwarn then                          (* if file warning is on *)
        checkname(fn);                       (* must check that name unique *)
  end; (* makename *)

  begin (* rfile *)
    if debug then
        debugwrite('rfile');

    if (numtry > maxtry) then         (* if too many tries, give up *)
      begin
        rfile := 'a';
        exit(rfile)
      end;
    numtry := numtry + 1;

    ch := rpack(len,num,recpkt);      (* receive a packet *)
    if debug and (ch<>chr(0)) then packetwrite(recpkt,len);
    refresh_screen(numtry,n);

    if ch = 'S' then                  (* send init, maybe our ACK lost *)
      begin
        if (oldtry > maxtry) then     (* too many tries, abort *)
          begin
            debugwrite('too many tries in rfile init');
            rfile := 'a';
            exit(rfile)
          end; (* if *)

        n := n - 1;

        if num = (n mod 64) then      (* previous packet mod 64? *)
          begin                       (* yes, ACK it again *)
            debugint('re-acking init ',num);
            spar(packet);             (* with our send init params *)
            spack('Y',num,7,packet);
            numtry := 0;              (* reset try counter *)
            rfile := state;           (* stay in same state *)
          end (* if *)
        else                          (* not previous packet, abort *)
          state := 'a'
      end (* if 'S' *)
    else if (ch = 'Z') then           (* end of file *)
      begin
        if (oldtry > maxtry) then     (* too many tries, abort *)
          begin
            debugwrite('too many tries in filehead eof');
            rfile := 'a';
            exit(rfile)
          end; (* if *)

        n := n - 1;

        if num = (n mod 64) then       (* previous packet mod 64? *)
          begin                       (* yes, ACK it again *)
            debugint('re-acking eof ',num);
            spack('Y',num,0,packet);
            numtry := 0;
            rfile := state            (* stay in same state *)
          end (* if *)
        else
            rfile := 'a'              (* no, abort *)
      end (* else if *)
    else if (ch = 'F') then           (* file header *)
      begin                           (* which is what we really want *)
        if (num <> (n mod 64)) then   (* if wrong packet, abort *)
          begin
            debugwrite('wrong seq. of file header');
            rfile := 'a';
            exit(rfile)
          end;

        makename(recpkt,filename,len); (* get filename, make unique if filew *)
        gotoxy(filepos,fileline);
        write(oldfn,' ==> ',filename);

        if not getfil(filename) then  (* try to open new file *)
          begin
            inoerror(ioresult);        (* if unsuccessful, tell them *)
            rfile := 'a';             (* and abort *)
            exit(rfile)
          end; (* if *)

        spack('Y',n mod 64,0,packet); (* ACK file header *)
        oldtry := numtry;             (* reset try counters *)
        numtry := 0;
        n := n + 1;                   (* bump packet number *)
        rfile := 'd';                 (* switch to data state *)
      end (* else if *)
    else if ch = 'B' then             (* break transmission *)
      begin
        if (num <> (n mod 64)) then            (* wrong packet, abort *)
          begin
            debugwrite('wrong sequence in break packet');
            rfile := 'a';
            exit(rfile)
          end;
        spack('Y',n mod 64,0,packet); (* say ok *)
        rfile := 'c'                  (* go to complete state *)
      end (* else if *)
    else if (ch = 'E') then
      begin
        error(recpkt,len);
        rfile := 'a'
      end
    else if (ch = chr(0)) then        (* returned false *)
        rfile := state                (* so stay in same state *)
    else begin                        (* some weird state, so abort *)
        rfile := 'a';
        debugwrite('wierd rfile packet');
        end
  end; (* rfile *)

function rbreak: char;

(* receive file header *)

var num, len: integer;
    ch: char;
    i: integer;

  begin (* rbreak *)
    if debug then
        debugwrite('rbreak');

    if (numtry > maxtry) then         (* if too many tries, give up *)
      begin
        rbreak := 'a';
        exit(rbreak)
      end;
    numtry := numtry + 1;

    ch := rpack(len,num,recpkt);      (* receive a packet *)
    if debug and (ch<>chr(0)) then packetwrite(recpkt,len);
    refresh_screen(numtry,n);
 
    if (ch = 'Z') then
      begin{ is previous eof packet }

      n := n -1;
      if (num = (n mod 64)) then (* previous packet again *)
        begin                (* so re-ACK it *)
          debugint('re-acking ',num);
          spack('Y',num,6,packet);
          numtry := 0;       (* reset try counter *)
                             (* stay in same state *)
        end (* if *)
      else begin             (* wrong number *)
          debugwrite('wrong data sequence no. in rbreak');
          state := 'a'       (* so abort *)
          end
      end
   else
    if ch = 'B' then             (* break transmission *)
      begin
        if (num <> (n mod 64)) then            (* wrong packet, abort *)
          begin
            debugwrite('wrong sequence in break packet');
            rbreak := 'a';
            exit(rbreak)
          end;
        spack('Y',n mod 64,0,packet); (* say ok *)
        rbreak := 'c'                  (* go to complete state *)
      end (* else if *)
    else if (ch = 'E') then
      begin
        error(recpkt,len);
        rbreak := 'a'
      end
    else if (ch = chr(0)) then        (* returned false *)
        rbreak := state                (* so stay in same state *)
    else begin                        (* some weird state, so abort *)
        rbreak := 'a';
        debugwrite('wierd break packet');
        end
  end; (* rbreak *)
 
function rinit: char;

(* receive initialization *)

var num, len: integer;  (* packet number and length *)
    ch: char;

  begin
    if debug then
        debugwrite('rinit');

    numtry := numtry + 1;

    ch := rpack(len,num,recpkt); (* receive a packet *)
    if debug and (ch<>chr(0)) then packetwrite(recpkt,len);
    refresh_screen(num_try,n);

    if (ch = 'S') then           (* send init packet *)
      begin
        rpar(recpkt);            (* get other side's init data *)
        spar(packet);            (* fill packet with my init data *)
        if TranState <> TxtFile then
          ctl_set := [chr(1)..chr(31),chr(del),quote,bquote]
         else
           ctl_set := [chr(1)..chr(31),chr(del),quote];
        spack('Y',n mod 64,7,packet); (* ACK with my params *)
        oldtry := numtry;        (* save old try count *)
        numtry := 0;             (* start a new counter *)
        n := n + 1;              (* bump packet number *)
        rinit := 'f';            (* enter file send state *)
      end (* if 'S' *)
    else if (ch = 'E') then
      begin
        rinit := 'a';
        error(recpkt,len)
      end (* if 'E' *)
    else if (ch = chr(0)) then
        rinit := 'r'             (* stay in same state *)
    else begin
        rinit := 'a';             (* abort *)
        debugwrite('wierd rinit packet');
        end
  end; (* rinit *)

(* state table switcher for receiving packets *)

  begin (* recswok *)
    writescreen('Receiving');
    state := 'r';            (* initial state is send *)
    n := 0;                  (* set packet # *)
    numtry := 0;             (* no tries yet *)

    while true do
        if state in ['d', 'f', 'r', 'c', 'a', 'b'] then
          case state of
              'd': state := rdata;
              'f': state := rfile;
              'r': state := rinit;
              'b': state := rbreak;
              'c': begin
                     rec_ok := true;
                     CloseF(filename,true);
                     exit(recsw)
                   end; (* case c *)
              'a': begin
                     rec_ok := false;
                     CloseF(filename,false);
                     exit(recsw)
                   end (* case a *)
            end (* case *)
        else (* state not in legal states *)
          begin
            rec_ok := false;
            CloseF(filename,False);
            exit(recsw)
          end (* else *)
  end; (* recsw *)

