117 lines
2.6 KiB
Python
117 lines
2.6 KiB
Python
|
import SocketServer
|
||
|
|
||
|
class FTPMessage:
|
||
|
def __init__(self,cmd,parameter):
|
||
|
self.cmd = cmd
|
||
|
self.parameter = parameter
|
||
|
|
||
|
def generate(self):
|
||
|
return "%s %s\r\n" % (self.cmd.upper(), self.parameter)
|
||
|
|
||
|
def __str__(self):
|
||
|
return self.generate()
|
||
|
|
||
|
@staticmethod
|
||
|
def parse(line):
|
||
|
pos = line.find(" ")
|
||
|
if pos == -1:
|
||
|
cmd = line
|
||
|
param = None
|
||
|
else:
|
||
|
cmd = line[:pos]
|
||
|
param = line[pos+1:]
|
||
|
return FTPMessage(cmd.upper(),param)
|
||
|
|
||
|
class GeneralState:
|
||
|
@staticmethod
|
||
|
def handle(self, message):
|
||
|
if message.cmd == "QUIT":
|
||
|
self.debug("Client wants to quit")
|
||
|
self.send(FTPMessage("221","Goodbye."))
|
||
|
self.handler.running = False
|
||
|
else:
|
||
|
self.debug("Unknown command %s" % message.cmd)
|
||
|
self.send(FTPMessage("500", "%s not understood" % message.cmd ))
|
||
|
|
||
|
class UserState:
|
||
|
@staticmethod
|
||
|
def handle(self, message):
|
||
|
if message.cmd == "USER":
|
||
|
self.debug("Initiating login for user %s" % message.parameter)
|
||
|
self.send(FTPMessage("331","Password required for %s" % message.parameter))
|
||
|
self.state = PassState
|
||
|
else:
|
||
|
GeneralState.handle(self, message)
|
||
|
|
||
|
class PassState:
|
||
|
@staticmethod
|
||
|
def handle(self, message):
|
||
|
if message.cmd == "PASS":
|
||
|
self.debug("Denying access with password %s" % message.parameter)
|
||
|
self.send(FTPMessage("530","Login incorrect."))
|
||
|
self.state = UserState
|
||
|
else:
|
||
|
GeneralState.handle(self, message)
|
||
|
|
||
|
class FTPMessageHandler:
|
||
|
def __init__(self, handler):
|
||
|
self.state = UserState
|
||
|
self.handler = handler
|
||
|
|
||
|
def send(self,data):
|
||
|
return self.handler.request.send( str(data) )
|
||
|
|
||
|
def debug(self,text):
|
||
|
self.handler.debug(text)
|
||
|
|
||
|
def handle(self, message):
|
||
|
self.state.handle(self, message)
|
||
|
|
||
|
class LineReader:
|
||
|
def __init__(self):
|
||
|
self.buf = ""
|
||
|
|
||
|
def push(self,data):
|
||
|
self.buf += data
|
||
|
|
||
|
def get_lines(self):
|
||
|
pos = self.buf.find("\n")
|
||
|
while pos != -1:
|
||
|
line = self.buf[:pos]
|
||
|
if line[-1] == "\r":
|
||
|
line = line[:-2]
|
||
|
yield line
|
||
|
self.buf = self.buf[pos+1:]
|
||
|
pos = self.buf.find("\n")
|
||
|
|
||
|
class FTPHandler(SocketServer.BaseRequestHandler):
|
||
|
def debug(self, text):
|
||
|
print ("[%s] " % self.client_address[0]) + text
|
||
|
|
||
|
def handle(self):
|
||
|
self.messagehandler = FTPMessageHandler(self)
|
||
|
|
||
|
self.debug("Client connected");
|
||
|
|
||
|
self.request.send(FTPMessage("220","FTP Server ready").generate())
|
||
|
|
||
|
linereader = LineReader()
|
||
|
|
||
|
self.running = True
|
||
|
|
||
|
while self.running:
|
||
|
data = self.request.recv(1024)
|
||
|
if len(data) == 0:
|
||
|
break
|
||
|
|
||
|
linereader.push(data)
|
||
|
|
||
|
for line in linereader.get_lines():
|
||
|
message = FTPMessage.parse(line)
|
||
|
self.messagehandler.handle(message)
|
||
|
|
||
|
self.debug("Client disconnected")
|
||
|
|
||
|
server = SocketServer.ThreadingTCPServer(("",1234),FTPHandler)
|
||
|
|
||
|
server.serve_forever()
|