#!/usr/bin/env python
# twisted_ftpget.py -- Fetch and display a file using anonymous FTP

SERVER   = 'ftp.freebsd.org'
USER     = 'anonymous'
PASSWD   = 'me@example.com'
SRCDIR   = '/pub/FreeBSD/releases/i386'
SRCFILE  = 'README.TXT'
DEBUG    = True   # Set to False for production code

from twisted.internet import reactor
from twisted.internet.protocol import Protocol, ClientCreator
from twisted.protocols.ftp import FTPClient
from cStringIO import StringIO

class BufferingProtocol(Protocol):
    def __init__(self): self.buffer = StringIO()
    def dataReceived(self, data): self.buffer.write(data)
filebufproto = BufferingProtocol()

def cb_success(response):
    if DEBUG: print 'OK', response
    return response
def cb_error(error):
    print 'ERR', error;
    reactor.stop()

def cb_changedir(ftpClient):
    if DEBUG: print 'cb_changedir()'
    dcwd = ftpClient.cwd(SRCDIR)
    dcwd.addCallbacks(cb_fetchfile, cb_error, callbackArgs=(ftpClient,))

def cb_fetchfile(result, ftpClient):
    if DEBUG: print 'cb_fetchfile() result:', result
    dfile = ftpClient.retrieveFile(SRCFILE, filebufproto)
    dfile.addCallbacks(cb_printfile, cb_error, callbackArgs=(ftpClient,))

def cb_printfile(result, ftpClient):
    if DEBUG: print 'cb_savefile() result:', result
    print filebufproto.buffer.getvalue(),  # print file contents
    dquit = ftpClient.quit()
    dquit.addCallbacks(lambda _: reactor.stop(), cb_error)

FTPClient.debug = DEBUG
client = ClientCreator(reactor, FTPClient, USER, PASSWD, passive=True)
dmain = client.connectTCP(SERVER, 21)
dmain.addCallbacks(cb_success, cb_error)
dmain.addCallbacks(cb_changedir, cb_error)
reactor.run()
