(*----------------------------------------------------------------*) procedure rheader; (* This procedure receives packets and looks for the file header packet. If a good file header packet is found, it attempts to open the file. If the file is opened suceesfully, the state changes to receive_file. If the file cannot be opened ( the file open procedure will attempt to create a unique filename if the sepcified file already exists) an error packet is returned to the requesting kermit. This procedure also handles send init packets and break packets as specified in the Kermit Protocol Manual. *) var try : integer; begin repeat receive_packet; if packet_ok then case packet_type of header_pack : begin open_file(write_open, rec_packet); if open_ok then begin filepointer := 1; (* postion at beginning of buffer *) packet_num := rec_packet_num; gotoxy(40,2); write('Receiving... '); send_ack; state := receive_file; end else begin packet_buffer := 'ECannot open file'; build_packet; send_packet; abort := true; gotoxy(1,9); writeln('Cannot open file: ',rec_packet); end; end; send_pack : begin packet_num := rec_packet_num; send_ack; end; break_pack : begin packet_num := rec_packet_num; send_ack; abort := true; gotoxy(60,1); write('Completed.'); gotoxy(1,10); end; end_pack : begin packet_num := rec_packet_num; send_ack; end; unknown : begin abort := true; packet_num := rec_packet_num; packet_buffer := 'EUnknown packet type.'; build_packet; send_packet; gotoxy(60,1); write('Aborted.'); gotoxy(1,10); end; end (* case *) else begin try := try + 1; packets_bad := packets_bad + 1; send_nak; if try = maxtry then begin abort := true; packet_num := 0; packet_buffer := 'ECannot get file header.'; build_packet; send_packet; gotoxy(1,9); writeln('Cannot get file header.'); end; end; until abort or (state = receive_file); end; procedure get; (* initiate server send *) (* This procedure attempts to initiate a server send. It will send an 'R' packet with the filename specified in arg2 as typed by the user. If a valid send init packet is received, the state changes receive_header. If a valid send init packet cannot be received, an error packet is sent to the other Kermit after the specified number of retries. *) var try : integer; init_ok : boolean; begin clrscr; displayr; packet_num := 0; packet_buffer_data := 'R' + arg1; build_packet; try := 0; repeat send_packet; receive_packet; if packet_ok and (packet_type = send_pack) then begin packet_num := rec_packet_num; (* insure we've got packet num ok *) check_init(init_ok); if init_ok then begin send_ack; state := receive_header; end; end; if packet_type = error_pack then begin gotoxy(1,9); writeln(rec_packet); abort := true; end; if not (init_ok or abort) then begin packets_bad := packets_bad + 1; try := try + 1; send_nak; end; if ((try = maxtry) or abort) then begin abort := true; packet_buffer_data := 'ECannot get send init packet'; build_packet; send_packet; gotoxy(1,9); writeln('Cannot get send_init packet.'); end; until abort or (state = receive_header); end; procedure rinit; (* This procedure waits for a send init packet. It is used when a receive command is typed by the user. Therefore this procedure will hang here until a valid send init packet is received, or the user aborts the process from the keyboard. *) var try : integer; init_ok : boolean; begin clrscr; displayr; try := 0; repeat receive_packet; if packet_ok and (packet_type = send_pack) then begin packet_num := rec_packet_num; check_init(init_ok); if init_ok then begin send_ack; state := receive_header; end; end else begin packets_bad := packets_bad + 1; send_nak; try := try + 1; if try = maxtry then begin abort := true; packet_buffer_data := 'ECannot get send init packet'; build_packet; send_packet; gotoxy(1,9); writeln('Cannot get send_init packet.'); end; end; until abort or (state = receive_header); end; procedure expand_packet; (* This procedure performs any conversions neccessary on the received packet data. It looks for the control quoting character and changes the character following it to the actual control character. It has been expanded to handle eighth bit quoting. It may be expanded later to handle repeat counts. Note: The output data - 'received data' is set to null at the beginning of the procedure. In order to have the string length correct, each new character is concatenated, not referenced by its position in the string. Input: rec_packet (global) Output: received_data (global) *) var inpos : integer; begin {expand_packet} received_data := ''; inpos := 1; while inpos <= length(rec_packet) do begin {while} if (rec_packet[inpos] = quote_8) and quoting then begin inpos := inpos +1; if rec_packet[inpos] = his_ctl_quote then begin inpos := inpos +1; if rec_packet[inpos] in ['#','&','~'] then received_data := received_data + chr(ord(rec_packet[inpos]) or $80) else received_data := received_data + ctl(chr(ord(rec_packet[inpos]) or $80)); end else received_data := received_data + chr(ord(rec_packet[inpos]) or $80); end else begin if (ord(rec_packet[inpos]) and $7f) = ord (his_ctl_quote) then begin if chr(ord(rec_packet[inpos]) and $7f) in ['#','~'] then received_data := received_data + rec_packet[inpos] else received_data := received_data + ctl(rec_packet[inpos]); end else received_data := received_data + rec_packet[inpos]; end; inpos := inpos +1; end; {while} end; {expand_packet} procedure rfile; (* This procedure receives file data from the remote Kermit. It will continue until a break packet, end of transmission packet, or an unknown packet is received. If there are too many retries, the procedure will abort, and an error packet will be sent to the other Kermit. *) var count, try : integer; begin repeat receive_packet; try := 0; case packet_ok of false : begin try := try + 1; if try = maxtry then begin abort := true; packet_buffer := 'EToo many retries.'; build_packet; send_packet; end else send_nak; end; true : begin if packet_num = rec_packet_num then send_ack else begin packet_num := rec_packet_num; case packet_type of data_pack : begin expand_packet; for count := 1 to length(received_data) do begin if filepointer > buffersize then begin blockwrite(outfile,filebuffer,1); filepointer := 1; buffer_num := buffer_num + 1; end; filebuffer[filepointer] := received_data[count]; filepointer := filepointer + 1; end; send_ack; end; end_pack : begin if file_open then (* send last record *) begin if file_type_var = ascii then if filepointer <= buffersize then filebuffer[filepointer] := ^Z; blockwrite(outfile,filebuffer,1); close(outfile); file_open := false; end; send_ack; state := receive_init; end; break_pack : begin if file_open then (* write last record *) begin if file_type_var = ascii then if filepointer <= buffersize then filebuffer[filepointer] := ^Z; blockwrite(outfile,filebuffer,1); close(outfile); file_open := false; end; send_ack; receive_done := true; end; unknown : begin send_nak; end; else (* valid but wrong kind of packet *) begin abort := true; end; end; (* case *) end; end; end; (* case *) until abort or receive_done; end; procedure receive; (* receive state switcher *) (* This is the receive state switcher. It will pass control to the apporpriate procedure as determined by each procedure above. *) begin packets_sent := 0; packets_bad := 0; buffer_num := 0;; (* for the byte count display *) receive_done := false; repeat case state of get_file : get; receive_init : rinit; receive_header : rheader; receive_file : rfile; end; (* case *) until (abort or receive_done); gotoxy(40,2); if receive_done then write('Completed. ') else write('Aborted. '); write(^G); gotoxy(1,10); (* get the cursor back below the display *) end; (* receive *)