"Fossies" - the Fresh Open Source Software Archive 
Member "getmail-5.16/getmailcore/_pop3ssl.py" (31 Oct 2021, 5940 Bytes) of package /linux/misc/getmail-5.16.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "_pop3ssl.py" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
5.15_vs_5.16.
1 #!/usr/bin/env python2
2 '''Provide an SSL-capable POP3 class.
3
4 '''
5
6 __all__ = [
7 'POP3_ssl_port',
8 'sslsocket',
9 'POP3SSL',
10 ]
11
12 import socket
13 from poplib import POP3, CR, LF, CRLF, error_proto
14
15 from getmailcore.exceptions import *
16 import getmailcore.logging
17 log = getmailcore.logging.Logger()
18
19 POP3_ssl_port = 995
20
21 class sslsocket(object):
22 '''The Python poplib.POP3() class mixes socket-like .sendall() and
23 file-like .readline() for communications. That would be okay, except that
24 the new socket.ssl objects provide only read() and write(), so they
25 don't act like a socket /or/ like a file. Argh.
26
27 This class takes a standard, connected socket.socket() object, sets it
28 to blocking mode (required for socket.ssl() to work correctly, though
29 apparently not documented), wraps .write() for .sendall() and implements
30 .readline().
31
32 The modified POP3 class below can then use this to provide POP3-over-SSL.
33
34 Thanks to Frank Benkstein for the inspiration.
35 '''
36 def __init__(self, sock, keyfile=None, certfile=None):
37 log.trace()
38 self.sock = sock
39 #self.sock.setblocking(1)
40 if keyfile and certfile:
41 self.ssl = socket.ssl(self.sock, keyfile, certfile)
42 else:
43 self.ssl = socket.ssl(self.sock)
44 self.buf = ''
45 self.bufsize = 128
46
47 def _fillbuf(self):
48 '''Fill an internal buffer for .readline() to use.
49 '''
50 log.trace()
51 want = self.bufsize - len(self.buf)
52 log.trace('want %i bytes\n' % want)
53 if want <= 0:
54 return
55 s = self.ssl.read(want)
56 got = len(s)
57 log.trace('got %i bytes\n' % got)
58 self.buf += s
59
60 def close(self):
61 self.sock.close()
62 self.ssl = None
63
64 # self.sock.sendall
65 def sendall(self, s):
66 # Maybe only set blocking around this call?
67 self.ssl.write(s)
68
69 # self.file.readline
70 def readline(self):
71 '''Simple hack to implement .readline() on a non-file object that
72 only supports .read().
73 '''
74 log.trace()
75 line = ''
76 try:
77 if not self.buf:
78 self._fillbuf()
79 log.trace('checking self.buf\n')
80 if self.buf:
81 log.trace('self.buf = "%r", len %i\n'
82 % (self.buf, len(self.buf)))
83 while True:
84 log.trace('looking for EOL\n')
85 i = self.buf.find('\n')
86 if i != -1:
87 log.trace('EOL found at %d\n' % i)
88 line += self.buf[:i + 1]
89 self.buf = self.buf[i + 1:]
90 break
91 # else
92 log.trace('EOL not found, trying to fill self.buf\n')
93 line += self.buf
94 self.buf = ''
95 self._fillbuf()
96 if not self.buf:
97 log.trace('nothing read, exiting\n')
98 break
99 log.trace('end of loop\n')
100 log.trace('returning line "%r"\n' % line)
101 return line
102 except (socket.sslerror, socket.error), o:
103 raise getmailOperationError(
104 'socket/ssl error while reading from server (%s)' % o
105 )
106
107 class POP3SSL(POP3):
108 '''Thin subclass to add SSL functionality to the built-in POP3 class.
109 Note that Python's socket module does not do certificate verification
110 for SSL connections.
111
112 This gets rid of the .file attribute from os.makefile(rawsock) and relies on
113 sslsocket() above to provide .readline() instead.
114 '''
115 def __init__(self, host, port=POP3_ssl_port, keyfile=None, certfile=None):
116 if not ((certfile and keyfile) or (keyfile == certfile == None)):
117 raise getmailConfigurationError('certfile requires keyfile')
118 self.host = host
119 self.port = port
120 msg = "getaddrinfo returns an empty list"
121 self.rawsock = None
122 self.sock = None
123 for res in socket.getaddrinfo(self.host, self.port, 0,
124 socket.SOCK_STREAM):
125 (af, socktype, proto, canonname, sa) = res
126 try:
127 self.rawsock = socket.socket(af, socktype, proto)
128 self.rawsock.connect(sa)
129 if certfile and keyfile:
130 self.sock = sslsocket(self.rawsock, keyfile, certfile)
131 else:
132 self.sock = sslsocket(self.rawsock)
133 except socket.error, msg:
134 if self.rawsock:
135 self.rawsock.close()
136 self.rawsock = None
137 continue
138 break
139 if not self.sock:
140 raise socket.error, msg
141 self._debugging = 0
142 self.welcome = self._getresp()
143
144 # Internal: return one line from the server, stripping CRLF.
145 # This is where all the CPU time of this module is consumed.
146 # Raise error_proto('-ERR EOF') if the connection is closed.
147 def _getline(self):
148 line = self.sock.readline()
149 if self._debugging > 1:
150 print '*get*', `line`
151 if not line:
152 raise error_proto('-ERR EOF')
153 octets = len(line)
154 # server can send any combination of CR & LF
155 # however, 'readline()' returns lines ending in LF
156 # so only possibilities are ...LF, ...CRLF, CR...LF
157 if line[-2:] == CRLF:
158 return line[:-2], octets
159 if line[0] == CR:
160 return line[1:-1], octets
161 return line[:-1], octets
162
163 def quit(self):
164 """Signoff: commit changes on server, unlock mailbox, close connection.
165 """
166 try:
167 resp = self._shortcmd('QUIT')
168 except (error_proto, socket.error), val:
169 resp = val
170 self.sock.close()
171 del self.sock
172 return resp