Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- """pypopper: a file-based pop3 server
- Useage:
- python pypopper.py <port> <path_to_message_file>
- """
- import logging
- import os
- import socket
- import sys
- import traceback
- logging.basicConfig(format="%(name)s %(levelname)s - %(message)s")
- log = logging.getLogger("pypopper")
- log.setLevel(logging.INFO)
- class ChatterboxConnection(object):
- END = "\r\n"
- def __init__(self, conn):
- self.conn = conn
- def __getattr__(self, name):
- return getattr(self.conn, name)
- def sendall(self, data, END=END):
- if len(data) < 50:
- log.debug("send: %r", data)
- else:
- log.debug("send: %r...", data[:50])
- data += END
- self.conn.sendall(data)
- def recvall(self, END=END):
- data = []
- while True:
- chunk = self.conn.recv(4096)
- if END in chunk:
- data.append(chunk[:chunk.index(END)])
- break
- data.append(chunk)
- if len(data) > 1:
- pair = data[-2] + data[-1]
- if END in pair:
- data[-2] = pair[:pair.index(END)]
- data.pop()
- break
- log.debug("recv: %r", "".join(data))
- return "".join(data)
- class Message(object):
- def __init__(self, filename):
- msg = open(filename, "r")
- try:
- self.data = data = msg.read()
- self.size = len(data)
- self.top, bot = data.split("\r\n\r\n", 1)
- self.bot = bot.split("\r\n")
- finally:
- msg.close()
- def handleUser(data, msg):
- return "+OK user accepted"
- def handlePass(data, msg):
- return "+OK pass accepted"
- def handleStat(data, msg):
- return "+OK 1 %i" % msg.size
- def handleList(data, msg):
- return "+OK 1 messages (%i octets)\r\n1 %i\r\n." % (msg.size, msg.size)
- def handleTop(data, msg):
- cmd, num, lines = data.split()
- assert num == "1", "unknown message number: %s" % num
- lines = int(lines)
- text = msg.top + "\r\n\r\n" + "\r\n".join(msg.bot[:lines])
- return "+OK top of message follows\r\n%s\r\n." % text
- def handleRetr(data, msg):
- log.info("message sent")
- return "+OK %i octets\r\n%s\r\n." % (msg.size, msg.data)
- def handleDele(data, msg):
- return "+OK message 1 deleted"
- def handleNoop(data, msg):
- return "+OK"
- def handleQuit(data, msg):
- return "+OK pypopper POP3 server signing off"
- dispatch = dict(
- USER=handleUser,
- PASS=handlePass,
- STAT=handleStat,
- LIST=handleList,
- TOP=handleTop,
- RETR=handleRetr,
- DELE=handleDele,
- NOOP=handleNoop,
- QUIT=handleQuit,
- )
- def serve(host, port, filename):
- assert os.path.exists(filename)
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- sock.bind((host, port))
- try:
- if host:
- hostname = host
- else:
- hostname = "localhost"
- log.info("pypopper POP3 serving '%s' on %s:%s", filename, hostname, port)
- while True:
- sock.listen(1)
- conn, addr = sock.accept()
- log.debug('Connected by %s', addr)
- try:
- msg = Message(filename)
- conn = ChatterboxConnection(conn)
- conn.sendall("+OK pypopper file-based pop3 server ready")
- while True:
- data = conn.recvall()
- command = data.split(None, 1)[0]
- try:
- cmd = dispatch[command]
- except KeyError:
- conn.sendall("-ERR unknown command")
- else:
- conn.sendall(cmd(data, msg))
- if cmd is handleQuit:
- break
- finally:
- conn.close()
- msg = None
- except (SystemExit, KeyboardInterrupt):
- log.info("pypopper stopped")
- except Exception, ex:
- log.critical("fatal error", exc_info=ex)
- finally:
- sock.shutdown(socket.SHUT_RDWR)
- sock.close()
- if __name__ == "__main__":
- if len(sys.argv) != 3:
- print "USAGE: [<host>:]<port> <path_to_message_file>"
- else:
- _, port, filename = sys.argv
- if ":" in port:
- host = port[:port.index(":")]
- port = port[port.index(":") + 1:]
- else:
- host = ""
- try:
- port = int(port)
- except Exception:
- print "Unknown port:", port
- else:
- if os.path.exists(filename):
- serve(host, port, filename)
- else:
- print "File not found:", filename
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement