diff --git a/src/myftp/client.py b/src/myftp/client.py index 96dbf91..21e0c52 100644 --- a/src/myftp/client.py +++ b/src/myftp/client.py @@ -119,17 +119,30 @@ class Client: # change command handling elif change_command_pattern.match(command): command_name, old_filename, new_filename = command.split() + print( f"myftp> - {self.protocol} - Changing file named {old_filename} into {new_filename} on the server" ) if self.debug else None + first_byte = (change_request_opcode << 5) + len(old_filename) + + second_byte_to_n_byte = ( + old_filename.encode("ascii") + + len(new_filename).to_bytes(1, "big") + + new_filename.encode("ascii") + ) + # unknown request, assigned opcode is 0b101 else: command_name = None first_byte: int = unknown_request_opcode << 5 - # get or put case - if command_name == "get" or command_name == "summary": + # get change put cases + if ( + command_name == "get" + or command_name == "summary" + or command_name == "change" + ): payload = first_byte.to_bytes(1, "big") + second_byte_to_n_byte # type: ignore elif command_name == "put": @@ -139,9 +152,6 @@ class Client: else first_byte.to_bytes(1, "big") # type: ignore ) - elif command == "change": - pass - # help case and unknown request else: payload: bytes = first_byte.to_bytes(1, "big") # type: ignore diff --git a/src/myftp/server.py b/src/myftp/server.py index a66bb99..0ac9b2c 100644 --- a/src/myftp/server.py +++ b/src/myftp/server.py @@ -138,6 +138,14 @@ class Server: filename_length_in_bytes, req_payload[1:] ) + elif request_type == "change": + rescode = self.process_change_req( + filename_length_in_bytes, req_payload[1:] + ) + filename_length_in_bytes = None + filename = None + response_data = None + elif request_type == "unknown": rescode = rescode_fail_dict["unknown_request_rescode"] filename_length_in_bytes = None @@ -188,6 +196,51 @@ class Server: return request_type, filename_length_in_bytes + def process_change_req( + self, old_filename_length_in_bytes: int, req_payload: bytes + ) -> int: + old_filename = req_payload[:old_filename_length_in_bytes].decode("ascii") + new_filename_length = int.from_bytes( + req_payload[ + old_filename_length_in_bytes : old_filename_length_in_bytes + 1 + ], + "big", + ) + new_filename = req_payload[old_filename_length_in_bytes + 1 :].decode("ascii") + + actual_new_filename_length = len(new_filename) + + try: + if new_filename_length <= 31 or actual_new_filename_length <= 31: + old_filename_full_path = os.path.normpath( + os.path.join(self.directory_path, old_filename) + ) + new_filename_full_path = os.path.normpath( + os.path.join(self.directory_path, new_filename) + ) + + print( + f"myftp> - {self.protocol} - Changing file named {old_filename_full_path} to new file {new_filename_full_path}" + ) + + os.rename(old_filename_full_path, new_filename_full_path) + + return rescode_success_dict["correct_put_and_change_request_rescode"] + + else: + print( + f"myftp> - {self.protocol} - New file name longer than 31 characters error" + ) + return rescode_fail_dict["unsuccessful_change_rescode"] + + except Exception as error: + traceback_info = traceback.format_exc() + + print(f"myftp> - {self.protocol} - {error} happened.") + + print(traceback_info) + return rescode_fail_dict["unsuccessful_change_rescode"] + def process_summary_req( self, filename_length: int, req_payload: bytes ) -> Tuple[int, Optional[str], Optional[int], Optional[bytes]]: @@ -335,7 +388,7 @@ class Server: # help case elif filename is None and response_data is not None: first_byte = ((rescode << 5) + len(response_data)).to_bytes(1, "big") - # unsuccessful cases + # other cases else: first_byte = (rescode << 5).to_bytes(1, "big")