示例#1
0
    def __init__(self, address, port):

        self.address = address
        self.port = port
        self.max_packet_length = 0xffff
        self.obex_version = OBEX_Version()
        self.response_handler = responses.ResponseHandler()

        self.socket = None
        self._external_socket = False
        self.connection_id = None
示例#2
0
    def __init__(self, mitsConnection):

    

        self.max_packet_length = 0x2000

        self.obex_version = OBEX_Version()

        self.response_handler = responses.ResponseHandler()

        

        self.con = mitsConnection

        self.connection_id = None
示例#3
0
    def read_data(self, data):

    

        # Extract the connection data from the complete data.

        extra_data = data[self.length(Message.format):self.minimum_length]

        

        obex_version, flags, max_packet_length = struct.unpack(

            ">"+self.format, extra_data

            )

        

        self.obex_version = OBEX_Version().from_byte(obex_version)

        self.flags = flags

        self.max_packet_length = max_packet_length

        

        Request.read_data(self, data)
示例#4
0
 def __init__(self, address="", log=lambda x: None):
     self.address = address
     self.max_packet_length = 0xffff
     self.obex_version = OBEX_Version()
     self.request_handler = requests.RequestHandler()
     self.methods = {
         requests.Connect: self.connect,
         requests.Disconnect: self.disconnect,
     }
     self.log = log
示例#5
0
    def __init__(self, address, port):

        self.address = address
        self.port = port
        self.max_packet_length = 0xFFFF
        self.obex_version = OBEX_Version()
        self.response_handler = responses.ResponseHandler()

        self.socket = None
        self._external_socket = False
        self.connection_id = None
示例#6
0
    def decode_connection(self, socket):

        code, length, data = self._read_packet(socket)

        if code == ConnectSuccess.code:
            message = ConnectSuccess()
        elif self.message_dict.has_key(code):
            message = self.message_dict[code]()
        else:
            return self.UnknownMessageClass(code, length, data)

        obex_version, flags, max_packet_length = struct.unpack(
            ">BBH", data[3:7])

        message.obex_version = OBEX_Version()
        message.obex_version.from_byte(obex_version)
        message.flags = flags
        message.max_packet_length = max_packet_length
        message.read_data(data)
        return message
示例#7
0
class Client(object):



    """Client

    

    client = Client(address, port)

    

    Provides common functionality for OBEX clients, including methods for

    connecting to and disconnecting from a server, sending and receiving

    headers, and methods for higher level actions such as "get", "put",

    "set path" and "abort".

    

    The address used is a standard six-field bluetooth address, and the port

    should correspond to the port providing the service you wish to access.

    """

    

    def __init__(self, mitsConnection):

    

        self.max_packet_length = 0x2000

        self.obex_version = OBEX_Version()

        self.response_handler = responses.ResponseHandler()

        

        self.con = mitsConnection

        self.connection_id = None

    

    def _send_headers(self, request, header_list, max_length):

    

        """Convenience method to add headers to a request and send one or

        more requests with those headers."""

        

        # Ensure that any Connection ID information is sent first.

        if self.connection_id:

            header_list.insert(0, self.connection_id)

        

        while header_list:

        

            if request.add_header(header_list[0], max_length):

                header_list.pop(0)

            else:

                self.con.send(request.encode())

                

                if isinstance(request, requests.Connect):

                    response = self.response_handler.decode_connection(self.con)

                else:

                    response = self.response_handler.decode(self.con)

                

                if not isinstance(response, responses.Continue):

                    return response

                

                request.reset_headers()

        

        # Always send at least one request.

        if isinstance(request, requests.Get):

            # Turn the last Get request containing the headers into a

            # Get_Final request.

            request.code = requests.Get_Final.code

        

        self.con.send(request.encode())



        print "Request",

        if isinstance(request, requests.Connect):

            print "connection..."

            response = self.response_handler.decode_connection(self.con)

        else:

            print "response.."

            response = self.response_handler.decode(self.con)

            

        print "OK"

        

        return response

    

    def _collect_parts(self, header_list):

    

        body = []

        new_headers = []

        for header in header_list:

        

            if isinstance(header, headers.Body):

                body.append(header.data)

            elif isinstance(header, headers.End_Of_Body):

                body.append(header.data)

            else:

                new_headers.append(header)

        

        return new_headers, "".join(body)

    

    def connect(self, header_list = ()):

    

        """connect(self, header_list = ())

        

        Sends a connection message to the server and returns its response.

        Typically, the response is either Success or a subclass of

        FailureResponse.

        

        Specific headers can be sent by passing a sequence as the

        header_list keyword argument.

        """

        

        flags = 0

        data = (self.obex_version.to_byte(), flags, self.max_packet_length)

        

        max_length = self.max_packet_length

        request = requests.Connect(data)

        

        header_list = list(header_list)

        response = self._send_headers(request, header_list, max_length)

        

        if isinstance(response, responses.ConnectSuccess):

            self.remote_info = response

            for header in response.header_data:

                if isinstance(header, headers.Connection_ID):

                    # Recycle the Connection ID data to create a new header

                    # for future use.

                    self.connection_id = headers.Connection_ID(header.decode())



        return response

    

    def disconnect(self, header_list = ()):

    

        """disconnect(self, header_list = ())

        

        Sends a disconnection message to the server and returns its response.

        Typically, the response is either Success or a subclass of

        FailureResponse.

        

        Specific headers can be sent by passing a sequence as the

        header_list keyword argument.

        

        If the socket was not supplied using set_socket(), it will be closed.

        """

        

        max_length = self.remote_info.max_packet_length

        request = requests.Disconnect()

        

        header_list = list(header_list)

        response = self._send_headers(request, header_list, max_length)

                

        self.connection_id = None

        

        return response

        

    def mobex_cmd(self, typ, name=None, extra_headers=()):

        header_list = [

            headers.Type(typ),

        ]

        if name is not None:

            header_list.append(headers.Name(name))

        header_list += extra_headers

        

        max_length = self.remote_info.max_packet_length

        request = requests.Put_Final()

        

        return self._send_headers(request, header_list, max_length)

        

    # TODO: Make this prettier

    def ugly_basic_response_error_check(self, cmdName, resp):

        if not isinstance(resp, responses.Success):

            raise Exception("%s: Got an unexpected mobex response type: '%s'" % (cmdName, type(resp)))

        for hdr in resp.header_data:

            dataLwr = hdr.data.lower()

            if "fail" in dataLwr or "err" in dataLwr:

                raise Exception("%s: Received failure response: %s" % (cmdName, str(resp)))

        

    def mobex_connection_packet(self):

        return self.mobex_cmd("m-obex/connection_packet")

        

    def mobex_create_folder(self, dirPath):

        resp = self.mobex_cmd("m-obex/fs/folder_create", dirPath)

        self.ugly_basic_response_error_check("folder_create", resp)

        return resp

        

        

    def mobex_delete_file(self, filePath):

        resp = self.mobex_cmd("m-obex/fs/file_delete", filePath)

        self.ugly_basic_response_error_check("file_delete", resp)

        return resp

    

    def put(self, name, file_data, header_list = ()):

    

        """put(self, name, file_data, header_list = ())

        

        Sends a file with the given name, containing the file_data specified,

        to the server for storage in the current directory for the session,

        and returns the response.

        

        Additional headers can be sent by passing a sequence as the

        header_list keyword argument. These will be sent after the name and

        file length information associated with the name and file_data

        supplied.

        """

        

        header_list = [

            headers.Name(name),

            headers.Length(len(file_data))

            ] + list(header_list)

        

        max_length = self.remote_info.max_packet_length

        request = requests.Put()

        

        response = self._send_headers(request, header_list, max_length)

        

        if not isinstance(response, responses.Continue):

            return response

        

        # Send the file data.

        

        # The optimum size is the maximum packet length accepted by the

        # remote device minus three bytes for the header ID and length

        # minus three bytes for the request.

        optimum_size = max_length - 3 - 3

        

        i = 0

        while i < len(file_data):

        

            data = file_data[i:i+optimum_size]

            i += len(data)

            if i < len(file_data):

                request = requests.Put()

                request.add_header(headers.Body(data, False), max_length)

                self.con.send(request.encode())

                

                response = self.response_handler.decode(self.con)

                

                if not isinstance(response, responses.Continue):

                    return response

            

            else:

                request = requests.Put_Final()

                request.add_header(headers.End_Of_Body(data, False), max_length)

                self.con.send(request.encode())

                

                response = self.response_handler.decode(self.con)

                

                if not isinstance(response, responses.Success):

                    return response

        

        return response

    

    def get(self, name = None, header_list = ()):

    

        """get(self, name = None, header_list = ())

        

        Requests the specified file from the server's current directory for

        the session. If successful, returns a tuple containing a list of

        responses received during the operation and the file data received.

        If unsuccessful, a single response object is returned.

        

        Additional headers can be sent by passing a sequence as the

        header_list keyword argument. These will be sent after the name

        information.

        """

        

        header_list = list(header_list)

        if name is not None:

            header_list = [headers.Name(name)] + header_list

        

        max_length = self.remote_info.max_packet_length

        request = requests.Get()

        

        response = self._send_headers(request, header_list, max_length)

        

        if not isinstance(response, responses.Continue) and \

            not isinstance(response, responses.Success):

        

            return response

        

        # Retrieve the file data.

        returned_headers = []

        file_data = []

        request = requests.Get_Final()

        

        while isinstance(response, responses.Continue):

        

            returned_headers += response.header_data

            

            self.con.send(request.encode())

            

            response = self.response_handler.decode(self.con)

        

        if not isinstance(response, responses.Success):

            return response

        

        returned_headers += response.header_data

        

        return self._collect_parts(returned_headers)

    

    def setpath(self, name = "", create_dir = False, to_parent = False, header_list = ()):

    

        """setpath(self, name = "", create_dir = False, to_parent = False, header_list = ())

        

        Requests a change to the server's current directory for the session

        to the directory with the specified name, and returns the response.

        

        This method is also used to perform other actions, such as navigating

        to the parent directory (set to_parent to True) and creating a new

        directory (set create_dir to True).

        

        Additional headers can be sent by passing a sequence as the

        header_list keyword argument. These will be sent after the name

        information.

        """

        

        header_list = list(header_list)

        if name is not None:

            header_list = [headers.Name(name)] + header_list

        

        max_length = self.remote_info.max_packet_length

        

        flags = 0

        if not create_dir:

            flags |= requests.Set_Path.DontCreateDir

        if to_parent:

            flags |= requests.Set_Path.NavigateToParent

        

        request = requests.Set_Path((flags, 0))

        

        response = self._send_headers(request, header_list, max_length)

        return response

    

    def abort(self, header_list = ()):

    

        """abort(self, header_list = ())

        

        Aborts the current session and returns the server's response.

        

        Specific headers can be sent by passing a sequence as the

        header_list keyword argument.

        

        Warning: This method should only be called to terminate a running

        operation and is therefore only useful for developers who want to

        reimplementing existing operations.

        """

        

        header_list = list(header_list)

        max_length = self.remote_info.max_packet_length

        request = requests.Abort()

        

        response = self._send_headers(request, header_list, max_length)

        return response
示例#8
0
class Client:
    """Client
    
    client = Client(address, port)
    
    Provides common functionality for OBEX clients, including methods for
    connecting to and disconnecting from a server, sending and receiving
    headers, and methods for higher level actions such as "get", "put",
    "set path" and "abort".
    
    The address used is a standard six-field bluetooth address, and the port
    should correspond to the port providing the service you wish to access.
    """
    def __init__(self, address, port):

        self.address = address
        self.port = port
        self.max_packet_length = 0xffff
        self.obex_version = OBEX_Version()
        self.response_handler = responses.ResponseHandler()

        self.socket = None
        self._external_socket = False
        self.connection_id = None

    def _send_headers(self, request, header_list, max_length):
        """Convenience method to add headers to a request and send one or
        more requests with those headers."""

        # Ensure that any Connection ID information is sent first.
        if self.connection_id:
            header_list.insert(0, self.connection_id)

        while header_list:

            if request.add_header(header_list[0], max_length):
                header_list.pop(0)
            else:
                self.socket.sendall(request.encode())

                if isinstance(request, requests.Connect):
                    response = self.response_handler.decode_connection(
                        self.socket)
                else:
                    response = self.response_handler.decode(self.socket)

                if not isinstance(response, responses.Continue):
                    return response

                request.reset_headers()

        # Always send at least one request.
        if isinstance(request, requests.Get):
            # Turn the last Get request containing the headers into a
            # Get_Final request.
            request.code = requests.Get_Final.code

        self.socket.sendall(request.encode())

        if isinstance(request, requests.Connect):
            response = self.response_handler.decode_connection(self.socket)
        else:
            response = self.response_handler.decode(self.socket)

        return response

    def _collect_parts(self, header_list):

        body = []
        new_headers = []
        for header in header_list:

            if isinstance(header, headers.Body):
                body.append(header.data)
            elif isinstance(header, headers.End_Of_Body):
                body.append(header.data)
            else:
                new_headers.append(header)

        return new_headers, "".join(body)

    def set_socket(self, socket):
        """set_socket(self, socket)
        
        Sets the socket to be used for communication to the socket specified.
        
        If socket is None, the client will create a socket for internal use
        when a connection is made. This is the default behaviour.
        
        This method must not be called once a connection has been opened.
        Only after an existing connection has been disconnected is it safe
        to set a new socket.
        """

        self.socket = socket

        if socket is None:
            self._external_socket = False
        else:
            self._external_socket = True

    def connect(self, header_list=()):
        """connect(self, header_list = ())
        
        Sends a connection message to the server and returns its response.
        Typically, the response is either Success or a subclass of
        FailureResponse.
        
        Specific headers can be sent by passing a sequence as the
        header_list keyword argument.
        """

        if not self._external_socket:
            self.socket = Socket()

        self.socket.connect((self.address, self.port))

        flags = 0
        data = (self.obex_version.to_byte(), flags, self.max_packet_length)

        max_length = self.max_packet_length
        request = requests.Connect(data)

        header_list = list(header_list)
        response = self._send_headers(request, header_list, max_length)

        if isinstance(response, responses.ConnectSuccess):
            self.remote_info = response
            for header in response.header_data:
                if isinstance(header, headers.Connection_ID):
                    # Recycle the Connection ID data to create a new header
                    # for future use.
                    self.connection_id = headers.Connection_ID(header.decode())

        elif not self._external_socket:
            self.socket.close()

        return response

    def disconnect(self, header_list=()):
        """disconnect(self, header_list = ())
        
        Sends a disconnection message to the server and returns its response.
        Typically, the response is either Success or a subclass of
        FailureResponse.
        
        Specific headers can be sent by passing a sequence as the
        header_list keyword argument.
        
        If the socket was not supplied using set_socket(), it will be closed.
        """

        max_length = self.remote_info.max_packet_length
        request = requests.Disconnect()

        header_list = list(header_list)
        response = self._send_headers(request, header_list, max_length)

        if not self._external_socket:
            self.socket.close()

        self.connection_id = None

        return response

    def put(self, name, file_data, header_list=(), callback=None):
        """put(self, name, file_data, header_list = (), callback = None)
        
        Sends a file with the given name, containing the file_data specified,
        to the server for storage in the current directory for the session.
        
        If a callback is specified, it will be called with each response
        obtained during the put operation. If no callback is specified, the
        final response is returned when the put operation is complete or an
        error occurs.
        
        Additional headers can be sent by passing a sequence as the
        header_list keyword argument. These will be sent after the name and
        file length information associated with the name and file_data
        supplied.
        """

        for response in self._put(name, header_list):

            if isinstance(response, responses.Continue) or \
                isinstance(response, responses.Success):

                # Report successful responses if using a callback.
                if callback:
                    callback(response)

            elif callback:
                # Report failure responses using the callback, then return.
                callback(response)
                return
            else:
                # Return failure responses directly.
                return response

        # Finally, return the last response if not using a callback.
        if not callback:
            return response

    def _put(self, name, file_data, header_list=()):

        header_list = [headers.Name(name),
                       headers.Length(len(file_data))] + list(header_list)

        max_length = self.remote_info.max_packet_length
        request = requests.Put()

        response = self._send_headers(request, header_list, max_length)
        yield response

        if not isinstance(response, responses.Continue):
            return

        # Send the file data.

        # The optimum size is the maximum packet length accepted by the
        # remote device minus three bytes for the header ID and length
        # minus three bytes for the request.
        optimum_size = max_length - 3 - 3

        i = 0
        while i < len(file_data):

            data = file_data[i:i + optimum_size]
            i += len(data)
            if i < len(file_data):
                request = requests.Put()
                request.add_header(headers.Body(data, False), max_length)
                self.socket.sendall(request.encode())

                response = self.response_handler.decode(self.socket)
                yield response

                if not isinstance(response, responses.Continue):
                    return

            else:
                request = requests.Put_Final()
                request.add_header(headers.End_Of_Body(data, False),
                                   max_length)
                self.socket.sendall(request.encode())

                response = self.response_handler.decode(self.socket)
                yield response

                if not isinstance(response, responses.Success):
                    return

    def get(self, name=None, header_list=(), callback=None):
        """get(self, name = None, header_list = (), callback = None)
        
        Requests the specified file from the server's current directory for
        the session.
        
        If a callback is specified, it will be called with each response
        obtained during the get operation. If no callback is specified, a value
        is returned which depends on the success of the operation.
        
        For an operation without callback, if successful, this method returns a
        tuple containing a list of responses received during the operation and
        the file data received; if unsuccessful, a single response object is
        returned.
        
        Additional headers can be sent by passing a sequence as the
        header_list keyword argument. These will be sent after the name
        information.
        """

        returned_headers = []

        for response in self._get(name, header_list):

            if isinstance(response, responses.Continue) or \
                isinstance(response, responses.Success):

                # Report successful responses if using a callback or collect
                # them for later.
                if callback:
                    callback(response)
                else:
                    returned_headers += response.header_data

            elif callback:
                # Report failure responses using the callback, then return.
                callback(response)
                return
            else:
                # Return failure responses directly.
                return response

        # Finally, return the collected responses if not using a callback.
        if not callback:
            return self._collect_parts(returned_headers)

    def _get(self, name=None, header_list=()):

        header_list = list(header_list)
        if name is not None:
            header_list = [headers.Name(name)] + header_list

        max_length = self.remote_info.max_packet_length
        request = requests.Get()

        response = self._send_headers(request, header_list, max_length)
        yield response

        if not isinstance(response, responses.Continue) and \
            not isinstance(response, responses.Success):

            return

        # Retrieve the file data.
        file_data = []
        request = requests.Get_Final()

        while isinstance(response, responses.Continue):

            self.socket.sendall(request.encode())

            response = self.response_handler.decode(self.socket)
            yield response

    def setpath(self,
                name="",
                create_dir=False,
                to_parent=False,
                header_list=()):
        """setpath(self, name = "", create_dir = False, to_parent = False, header_list = ())
        
        Requests a change to the server's current directory for the session
        to the directory with the specified name, and returns the response.
        
        This method is also used to perform other actions, such as navigating
        to the parent directory (set to_parent to True) and creating a new
        directory (set create_dir to True).
        
        Additional headers can be sent by passing a sequence as the
        header_list keyword argument. These will be sent after the name
        information.
        """

        header_list = list(header_list)
        if name is not None:
            header_list = [headers.Name(name)] + header_list

        max_length = self.remote_info.max_packet_length

        flags = 0
        if not create_dir:
            flags |= requests.Set_Path.DontCreateDir
        if to_parent:
            flags |= requests.Set_Path.NavigateToParent

        request = requests.Set_Path((flags, 0))

        response = self._send_headers(request, header_list, max_length)
        return response

    def delete(self, name, header_list=()):
        """delete(self, name, header_list = ())
        
        Requests the deletion of the file with the specified name from the
        current directory and returns the server's response.
        """

        header_list = [headers.Name(name)] + list(header_list)

        max_length = self.remote_info.max_packet_length
        request = requests.Put_Final()

        return self._send_headers(request, header_list, max_length)

    def abort(self, header_list=()):
        """abort(self, header_list = ())
        
        Aborts the current session and returns the server's response.
        
        Specific headers can be sent by passing a sequence as the
        header_list keyword argument.
        
        Warning: This method should only be called to terminate a running
        operation and is therefore only useful for developers who want to
        reimplementing existing operations.
        """

        header_list = list(header_list)
        max_length = self.remote_info.max_packet_length
        request = requests.Abort()

        response = self._send_headers(request, header_list, max_length)
        return response
示例#9
0
class Client:

    """Client
    
    client = Client(address, port)
    
    Provides common functionality for OBEX clients, including methods for
    connecting to and disconnecting from a server, sending and receiving
    headers, and methods for higher level actions such as "get", "put",
    "set path" and "abort".
    
    The address used is a standard six-field bluetooth address, and the port
    should correspond to the port providing the service you wish to access.
    """

    def __init__(self, address, port):

        self.address = address
        self.port = port
        self.max_packet_length = 0xFFFF
        self.obex_version = OBEX_Version()
        self.response_handler = responses.ResponseHandler()

        self.socket = None
        self._external_socket = False
        self.connection_id = None

    def _send_headers(self, request, header_list, max_length):

        """Convenience method to add headers to a request and send one or
        more requests with those headers."""

        # Ensure that any Connection ID information is sent first.
        if self.connection_id:
            header_list.insert(0, self.connection_id)

        while header_list:

            if request.add_header(header_list[0], max_length):
                header_list.pop(0)
            else:
                self.socket.sendall(request.encode())

                if isinstance(request, requests.Connect):
                    response = self.response_handler.decode_connection(self.socket)
                else:
                    response = self.response_handler.decode(self.socket)

                if not isinstance(response, responses.Continue):
                    return response

                request.reset_headers()

        # Always send at least one request.
        if isinstance(request, requests.Get):
            # Turn the last Get request containing the headers into a
            # Get_Final request.
            request.code = requests.Get_Final.code

        self.socket.sendall(request.encode())

        if isinstance(request, requests.Connect):
            response = self.response_handler.decode_connection(self.socket)
        else:
            response = self.response_handler.decode(self.socket)

        return response

    def _collect_parts(self, header_list):

        body = []
        new_headers = []
        for header in header_list:

            if isinstance(header, headers.Body):
                body.append(header.data)
            elif isinstance(header, headers.End_Of_Body):
                body.append(header.data)
            else:
                new_headers.append(header)

        return new_headers, "".join(body)

    def set_socket(self, socket):

        """set_socket(self, socket)
        
        Sets the socket to be used for communication to the socket specified.
        
        If socket is None, the client will create a socket for internal use
        when a connection is made. This is the default behaviour.
        
        This method must not be called once a connection has been opened.
        Only after an existing connection has been disconnected is it safe
        to set a new socket.
        """

        self.socket = socket

        if socket is None:
            self._external_socket = False
        else:
            self._external_socket = True

    def connect(self, header_list=()):

        """connect(self, header_list = ())
        
        Sends a connection message to the server and returns its response.
        Typically, the response is either Success or a subclass of
        FailureResponse.
        
        Specific headers can be sent by passing a sequence as the
        header_list keyword argument.
        """

        if not self._external_socket:
            self.socket = Socket()

        self.socket.connect((self.address, self.port))

        flags = 0
        data = (self.obex_version.to_byte(), flags, self.max_packet_length)

        max_length = self.max_packet_length
        request = requests.Connect(data)

        header_list = list(header_list)
        response = self._send_headers(request, header_list, max_length)

        if isinstance(response, responses.ConnectSuccess):
            self.remote_info = response
            for header in response.header_data:
                if isinstance(header, headers.Connection_ID):
                    # Recycle the Connection ID data to create a new header
                    # for future use.
                    self.connection_id = headers.Connection_ID(header.decode())

        elif not self._external_socket:
            self.socket.close()

        return response

    def disconnect(self, header_list=()):

        """disconnect(self, header_list = ())
        
        Sends a disconnection message to the server and returns its response.
        Typically, the response is either Success or a subclass of
        FailureResponse.
        
        Specific headers can be sent by passing a sequence as the
        header_list keyword argument.
        
        If the socket was not supplied using set_socket(), it will be closed.
        """

        max_length = self.remote_info.max_packet_length
        request = requests.Disconnect()

        header_list = list(header_list)
        response = self._send_headers(request, header_list, max_length)

        if not self._external_socket:
            self.socket.close()

        self.connection_id = None

        return response

    def put(self, name, file_data, header_list=(), callback=None):

        """put(self, name, file_data, header_list = (), callback = None)
        
        Sends a file with the given name, containing the file_data specified,
        to the server for storage in the current directory for the session.
        
        If a callback is specified, it will be called with each response
        obtained during the put operation. If no callback is specified, the
        final response is returned when the put operation is complete or an
        error occurs.
        
        Additional headers can be sent by passing a sequence as the
        header_list keyword argument. These will be sent after the name and
        file length information associated with the name and file_data
        supplied.
        """
        for response in self._put(name, file_data, header_list):

            if isinstance(response, responses.Continue) or isinstance(response, responses.Success):

                # Report successful responses if using a callback.
                if callback:
                    callback(response)

            elif callback:
                # Report failure responses using the callback, then return.
                callback(response)
                return
            else:
                # Return failure responses directly.
                return response

        # Finally, return the last response if not using a callback.
        if not callback:
            return response

    def _put(self, name, file_data, header_list=()):

        header_list = [headers.Name(name), headers.Length(len(file_data)), headers.End_Of_Body(file_data)] + list(
            header_list
        )

        max_length = self.remote_info.max_packet_length
        request = requests.Put()
        response = self._send_headers(request, header_list, max_length)
        yield response

        if not isinstance(response, responses.Continue):
            return

        # Send the file data.

        # The optimum size is the maximum packet length accepted by the
        # remote device minus three bytes for the header ID and length
        # minus three bytes for the request.
        optimum_size = max_length - 3 - 3

        i = 0
        while i < len(file_data):

            data = file_data[i : i + optimum_size]
            i += len(data)
            if i < len(file_data):
                request = requests.Put()
                request.add_header(headers.Body(data, False), max_length)
                self.socket.sendall(request.encode())

                response = self.response_handler.decode(self.socket)
                yield response

                if not isinstance(response, responses.Continue):
                    return

            else:
                request = requests.Put_Final()
                request.add_header(headers.End_Of_Body(data, False), max_length)
                self.socket.sendall(request.encode())

                response = self.response_handler.decode(self.socket)
                yield response

                if not isinstance(response, responses.Success):
                    return

    def get(self, name=None, header_list=(), callback=None):

        """get(self, name = None, header_list = (), callback = None)
        
        Requests the specified file from the server's current directory for
        the session.
        
        If a callback is specified, it will be called with each response
        obtained during the get operation. If no callback is specified, a value
        is returned which depends on the success of the operation.
        
        For an operation without callback, if successful, this method returns a
        tuple containing a list of responses received during the operation and
        the file data received; if unsuccessful, a single response object is
        returned.
        
        Additional headers can be sent by passing a sequence as the
        header_list keyword argument. These will be sent after the name
        information.
        """

        returned_headers = []

        for response in self._get(name, header_list):

            if isinstance(response, responses.Continue) or isinstance(response, responses.Success):

                # Report successful responses if using a callback or collect
                # them for later.
                if callback:
                    callback(response)
                else:
                    returned_headers += response.header_data

            elif callback:
                # Report failure responses using the callback, then return.
                callback(response)
                return
            else:
                # Return failure responses directly.
                return response

        # Finally, return the collected responses if not using a callback.
        if not callback:
            return self._collect_parts(returned_headers)

    def _get(self, name=None, header_list=()):

        header_list = list(header_list)
        if name is not None:
            header_list = [headers.Name(name)] + header_list

        max_length = self.remote_info.max_packet_length
        request = requests.Get()

        response = self._send_headers(request, header_list, max_length)
        yield response

        if not isinstance(response, responses.Continue) and not isinstance(response, responses.Success):

            return

        # Retrieve the file data.
        file_data = []
        request = requests.Get_Final()

        while isinstance(response, responses.Continue):

            self.socket.sendall(request.encode())

            response = self.response_handler.decode(self.socket)
            yield response

    def setpath(self, name="", create_dir=False, to_parent=False, header_list=()):

        """setpath(self, name = "", create_dir = False, to_parent = False, header_list = ())
        
        Requests a change to the server's current directory for the session
        to the directory with the specified name, and returns the response.
        
        This method is also used to perform other actions, such as navigating
        to the parent directory (set to_parent to True) and creating a new
        directory (set create_dir to True).
        
        Additional headers can be sent by passing a sequence as the
        header_list keyword argument. These will be sent after the name
        information.
        """

        header_list = list(header_list)
        if name is not None:
            header_list = [headers.Name(name)] + header_list

        max_length = self.remote_info.max_packet_length

        flags = 0
        if not create_dir:
            flags |= requests.Set_Path.DontCreateDir
        if to_parent:
            flags |= requests.Set_Path.NavigateToParent

        request = requests.Set_Path((flags, 0))

        response = self._send_headers(request, header_list, max_length)
        return response

    def delete(self, name, header_list=()):

        """delete(self, name, header_list = ())
        
        Requests the deletion of the file with the specified name from the
        current directory and returns the server's response.
        """

        header_list = [headers.Name(name)] + list(header_list)

        max_length = self.remote_info.max_packet_length
        request = requests.Put_Final()

        return self._send_headers(request, header_list, max_length)

    def abort(self, header_list=()):

        """abort(self, header_list = ())
        
        Aborts the current session and returns the server's response.
        
        Specific headers can be sent by passing a sequence as the
        header_list keyword argument.
        
        Warning: This method should only be called to terminate a running
        operation and is therefore only useful for developers who want to
        reimplementing existing operations.
        """

        header_list = list(header_list)
        max_length = self.remote_info.max_packet_length
        request = requests.Abort()

        response = self._send_headers(request, header_list, max_length)
        return response