'Given the current state, returns the next packet we should send
to the client'

def reply(self):

    if (self.state == TFTP_OPCODE_ACK):
        offset = (self.block_count * self.options['blksize'])
        if (self.file_size < offset):
            logging.info(('Transfer    of    %s    to    %s    done' % (self.filename, self.remote_addr)))
            return None
        self.file.seek((self.block_count * self.options['blksize']))
        data = self.file.read(self.options['blksize'])
        self.state = TFTP_OPCODE_DATA
        logging.log(9, ('DATA    to    %s/%d,    block_count    %d/%d,    size    %d(%d/%d)' % (self.remote_addr[0], self.remote_addr[1], (self.block_count + 1), ((self.block_count + 1) & 65535), len(data), (offset + len(data)), self.file_size)))
        return DATAPacket(data, (self.block_count + 1))
    if (self.state == 0):
        return None
    if (self.state == TFTP_OPCODE_ERROR):
        return ERRORPacket(self.error_code, self.error_str)
    if ((self.state == TFTP_OPCODE_RRQ) and self.req_options):
        self.state = TFTP_OPCODE_OACK
        self._setup_xfer()
        if (self.state == TFTP_OPCODE_ERROR):
            return ERRORPacket(self.error_code, self.error_str)
        self.options = dict(blksize=OPTIONS['blksize'], timeout=OPTIONS['timeout'])
        accepted_opts = []
        logging.debug(('Requested    options:    %s' % repr(self.req_options)))
        for i in range(0, len(self.req_options), 2):
            key = self.req_options[i]
            value = self.req_options[(i + 1)]
            logging.debug(('looking    at    key    %s' % key))
            if (key.lower() == 'tsize'):
                accepted_opts.append(key)
                accepted_opts.append(self.file_size)
            elif (('min_' + key).lower() in OPTIONS):
                value = int(value)
                upper_bound = OPTIONS[('max_' + key).lower()]
                lower_bound = OPTIONS[('min_' + key).lower()]
                logging.debug(('%s:    req:    %d    (%d    -    %d)' % (key, value, lower_bound, upper_bound)))
                if (value < lower_bound):
                    value = lower_bound
                if (value > upper_bound):
                    value = upper_bound
                self.options[key.lower()] = value
                accepted_opts.append(key)
                accepted_opts.append(str(value))
            else:
                logging.info(('Unknown    option    requested    %s' % key))
        logging.debug(('Using    Options:    %s' % repr(self.options)))
        return OACKPacket(accepted_opts)
    if (self.state == TFTP_OPCODE_RRQ):
        self.options = dict(blksize=OPTIONS['blksize'], timeout=OPTIONS['timeout'])
        logging.debug(('Using    Options:    %s' % repr(self.options)))
        self.state = TFTP_OPCODE_ACK
        self._setup_xfer()
        if (self.state == TFTP_OPCODE_ERROR):
            return ERRORPacket(self.error_code, self.error_str)
        return self.reply()
    raise NotImplementedError(('Unknown    state    %d' % self.state))
