-
Notifications
You must be signed in to change notification settings - Fork 0
/
pop3.py
147 lines (128 loc) · 3.39 KB
/
pop3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import socket
import ssl
CR = b'\r'
LF = b'\n'
CRLF = CR + LF
class Pop3:
def __init__(self, host, port):
"""
:type host: str
:type port: int
"""
self.host = host
self.port = port
self.sock = self.create_socket()
self.file = self.sock.makefile('rb')
self.welcome = self.get_resp()
def create_socket(self):
"""Returns ssl-wrapped socket"""
sock = socket.create_connection((self.host, self.port))
sock = ssl.wrap_socket(sock)
return sock
def get_line(self):
"""Returns line from server"""
line = self.file.readline()
if not line:
raise EOFError('-ERR EOF')
if line[-2:] == CRLF:
return line[:-2]
if line[:1] == CR:
return line[1:-1]
return line[:-1]
def get_resp(self):
"""
Returns singleline response
or raises come error
"""
resp = self.get_line()
if not resp.startswith(b'+'):
raise ConnectionError(resp)
return resp
def get_long_resp(self):
"""Returns multiline response"""
resp = self.get_resp()
lines = []
line = self.get_line()
while line != b'.':
if line.startswith(b'..'):
line = line[1:]
lines.append(line)
line = self.get_line()
return resp, lines
def send_bytes(self, line):
"""
Send line to server
:param line: bytes
"""
self.sock.sendall(line + CRLF)
def send_string(self, line):
"""
Send line to server
:param line: str
"""
self.send_bytes(line.encode())
def short_cmd(self, line):
"""
Send command
Returns singleline response
:param line: str
"""
self.send_string(line)
return self.get_resp()
def long_cmd(self, line):
"""
Send command
Returns multiline response
:param line: str
"""
self.send_string(line)
return self.get_long_resp()
def user(self, user):
"""
USER command
:param user: str
"""
return self.short_cmd('USER %s' % user)
def pass_(self, pswd):
"""
PASS command
:param pswd: str
"""
return self.short_cmd('PASS %s' % pswd)
def stat(self):
"""STAT command"""
return self.short_cmd('STAT')
def list_(self):
"""LIST command"""
return self.long_cmd('LIST')
def retr(self, which):
"""
RETR command
:param which: has __str__
"""
return self.long_cmd('RETR %s' % which)
def noop(self):
"""NOOP command"""
return self.short_cmd('NOOP')
def close(self):
"""Closes the socket"""
try:
file = self.file
self.file = None
if file is not None:
file.close()
finally:
sock = self.sock
self.sock = None
if sock is not None:
try:
sock.shutdown(socket.SHUT_RDWR)
except OSError:
return
finally:
sock.close()
def quit(self):
"""Closes the connection"""
resp = self.short_cmd('QUIT')
self.close()
return resp