Skip to content

Instantly share code, notes, and snippets.

@yszou
Created December 9, 2013 11:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yszou/7870960 to your computer and use it in GitHub Desktop.
Save yszou/7870960 to your computer and use it in GitHub Desktop.
Tornado实现的简单POP客户端
# -*- coding: utf-8 -*-
import logging
import socket
import uuid
import tornado.ioloop
import tornado.iostream
import tornado.gen
IL = tornado.ioloop.IOLoop.instance()
logger = logging.getLogger('AceFetch.POP')
class POP(object):
'POP服务'
def __init__(self, host, port, username='', password='', callback=None, ssl=False):
self.host = host
self.port = port
self.username = username
self.password = password
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
self.stream = tornado.iostream.IOStream(self.socket) if not ssl else tornado.iostream.SSLIOStream(self.socket)
self.callback = callback
self.stream.connect((self.host, self.port), self.on_connect)
@tornado.gen.engine
def send(self, cmd, args, callback, endswith='\r\n'):
cmd_id = uuid.uuid4().hex[:8]
logger.info('%s|%s|%s' % (cmd_id, cmd, args if cmd != 'pass' else '***'))
m = '%s %s\r\n' % (cmd, args) if args else '%s\r\n' % cmd
self.stream.write(m)
data = (yield tornado.gen.Task(self.stream.read_until, endswith)).strip()
method = logger.info if data.startswith('+OK') else logger.error
method('%s|%s|%s|%s' % (cmd_id, cmd, args if cmd != 'pass' else '***', data[:128]))
callback(data)
@tornado.gen.engine
def on_connect(self):
data = yield tornado.gen.Task(self.stream.read_until, '\r\n')
logger.info('on connected, %s' % data.strip())
if not data.startswith('+OK'):
self.close()
raise StopIteration
data = yield tornado.gen.Task(self.send, 'user', self.username)
if not data.startswith('+OK'):
self.close()
raise StopIteration
data = yield tornado.gen.Task(self.send, 'pass', self.password)
if not data.startswith('+OK'):
self.close()
raise StopIteration
if self.callback:
self.callback(self)
else:
self.close()
def close(self):
self.quit(lambda s: None)
self.stream.close()
logger.info('connection closed')
def stat(self, callback):
self.send('stat', '', callback)
def list(self, msg_number, callback):
endswith = '\r\n' if msg_number else '.\r\n'
self.send('list', msg_number, callback, endswith)
def retr(self, msg_number, callback):
if not msg_number:
callback('error, need a msg_number')
self.send('retr', msg_number, callback, '\r\n.\r\n')
def top(self, msg_number, top, callback):
if not msg_number:
callback('error, need a msg_number')
self.send('top', '%s %s' % (msg_number, top), callback, '\r\n.\r\n')
def rset(self, callback):
self.send('rset', '', callback)
def uidl(self, msg_number, callback):
endswith = '\r\n' if msg_number else '.\r\n'
self.send('uidl', msg_number, callback, endswith)
def dele(self, msg_number, callback):
if not msg_number:
callback('error, need a msg_number')
self.send('dele', msg_number, callback)
def noop(self, callback):
self.send('noop', '', callback)
def quit(self, callback):
self.send('quit', '', callback)
if __name__ == '__main__':
import getpass
@tornado.gen.engine
def test(pop):
data = yield tornado.gen.Task(pop.stat)
data = yield tornado.gen.Task(pop.list, '')
#data = yield tornado.gen.Task(pop.list, '6')
#data = yield tornado.gen.Task(pop.retr, '6')
#data = yield tornado.gen.Task(pop.top, '6', '0')
#data = yield tornado.gen.Task(pop.rset)
data = yield tornado.gen.Task(pop.uidl, '')
#data = yield tornado.gen.Task(pop.noop)
pop.close()
pwd = getpass.getpass('password: ')
#POP('mail.xx.com', 110, 'xxx@sohu-inc.com', pwd, test)
POP('pop.163.com', 110, 'xxx@163.com', pwd, test)
#POP('pop.gmail.com', 995, 'xxx@gmail.com', pwd, test, ssl=True)
IL.start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment