Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
d68af6d1
Commit
d68af6d1
authored
Apr 09, 1998
by
Guido van Rossum
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Version with docstrings and some other changes, by Piers Lauder.
(Adapted by Just, I believe.)
parent
65516c1d
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
201 additions
and
88 deletions
+201
-88
Lib/poplib.py
Lib/poplib.py
+201
-88
No files found.
Lib/poplib.py
View file @
d68af6d1
"""A POP3 client class.
Based on the J. Myers POP3 draft, Jan. 96
"""A POP3 client class.
Author: David Ascher <david_ascher@brown.edu> [heavily stealing from
nntplib.py]
Based on the J. Myers POP3 draft, Jan. 96
Author: David Ascher <david_ascher@brown.edu>
[heavily stealing from nntplib.py]
Updated: Piers Lauder <piers@cs.su.oz.au> [Jul '97]
"""
__version__
=
"0.01a - Feb 1, 1996 (with formatting changes by GvR)"
# Example (see the test function at the end of this file)
TESTSERVER
=
"localhost"
...
...
@@ -15,43 +15,64 @@ TESTPASSWORD = "_passwd_"
# Imports
from
types
import
StringType
import
regex
import
socket
import
string
import
regex
,
socket
,
string
# Exception raised when an error or invalid response is received:
error_proto
=
'pop3.error_proto'
# response does not begin with +
class
error_proto
(
Exception
):
pass
# Standard Port
POP3_PORT
=
110
# Line terminators (we always output CRLF, but accept any of CRLF, CR, LF)
CRLF
=
'
\
r
\
n
'
# This library supports both the minimal and optional command sets:
# Arguments can be strings or integers (where appropriate)
# (e.g.: retr(1) and retr('1') both work equally well.
#
# Minimal Command Set:
# USER name user(name)
# PASS string pass_(string)
# STAT stat()
# LIST [msg] list(msg = None)
# RETR msg retr(msg)
# DELE msg dele(msg)
# NOOP noop()
# RSET rset()
# QUIT quit()
#
# Optional Commands (some servers support these)
# APOP name digest apop(name, digest)
# TOP msg n top(msg, n)
# UIDL [msg] uidl(msg = None)
#
# Line terminators (we always output CRLF, but accept any of CRLF, LFCR, LF)
CR
=
'
\
r
'
LF
=
'
\
n
'
CRLF
=
CR
+
LF
class
POP3
:
"""This class supports both the minimal and optional command sets.
Arguments can be strings or integers (where appropriate)
(e.g.: retr(1) and retr('1') both work equally well.
Minimal Command Set:
USER name user(name)
PASS string pass_(string)
STAT stat()
LIST [msg] list(msg = None)
RETR msg retr(msg)
DELE msg dele(msg)
NOOP noop()
RSET rset()
QUIT quit()
Optional Commands (some servers support these):
RPOP name rpop(name)
APOP name digest apop(name, digest)
TOP msg n top(msg, n)
UIDL [msg] uidl(msg = None)
Raises one exception: 'error_proto'.
Instantiate with:
POP3(hostname, port=110)
NB: the POP protocol locks the mailbox from user
authorisation until QUIT, so be sure to get in, suck
the messages, and quit, each time you access the
mailbox.
POP is a line-based protocol, which means large mail
messages consume lots of python cycles reading them
line-by-line.
If it's available on your mail server, use IMAP4
instead, it doesn't suffer from the two problems
above.
"""
def
__init__
(
self
,
host
,
port
=
POP3_PORT
):
self
.
host
=
host
self
.
port
=
port
...
...
@@ -61,130 +82,222 @@ class POP3:
self
.
_debugging
=
0
self
.
welcome
=
self
.
_getresp
()
def
_putline
(
self
,
line
):
line
=
line
+
CRLF
if
self
.
_debugging
>
1
:
print
'*put*'
,
`line`
self
.
sock
.
send
(
line
)
#if self._debugging > 1: print '*put*', `line`
self
.
sock
.
send
(
'%s%s'
%
(
line
,
CRLF
))
# Internal: send one command to the server (through _putline())
def
_putcmd
(
self
,
line
):
if
self
.
_debugging
:
print
'*cmd*'
,
`line`
#
if self._debugging: print '*cmd*', `line`
self
.
_putline
(
line
)
# Internal: return one line from the server, stripping CRLF.
# Raise EOFError if the connection is closed
# This is where all the CPU time of this module is consumed.
# Raise error_proto('-ERR EOF') if the connection is closed.
def
_getline
(
self
):
line
=
self
.
file
.
readline
()
if
self
.
_debugging
>
1
:
print
'*get*'
,
`line`
if
not
line
:
raise
EOFError
if
line
[
-
2
:]
==
CRLF
:
line
=
line
[:
-
2
]
elif
line
[
-
1
:]
in
CRLF
:
line
=
line
[:
-
1
]
return
line
#if self._debugging > 1: print '*get*', `line`
if
not
line
:
raise
error_proto
(
'-ERR EOF'
)
octets
=
len
(
line
)
# server can send any combination of CR & LF
# however, 'readline()' returns lines ending in LF
# so only possibilities are ...LF, ...CRLF, CR...LF
if
line
[
-
2
:]
==
CRLF
:
return
line
[:
-
2
],
octets
if
line
[
0
]
==
CR
:
return
line
[
1
:
-
1
],
octets
return
line
[:
-
1
],
octets
# Internal: get a response from the server.
# Raise various errors if the response indicates an error
# Raise 'error_proto' if the response doesn't start with '+'.
def
_getresp
(
self
):
resp
=
self
.
_getline
()
if
self
.
_debugging
>
1
:
print
'*resp*'
,
`resp`
resp
,
o
=
self
.
_getline
()
#
if self._debugging > 1: print '*resp*', `resp`
c
=
resp
[:
1
]
if
c
!=
'+'
:
raise
error_proto
,
resp
raise
error_proto
(
resp
)
return
resp
# Internal: get a response plus following text from the server.
# Raise various errors if the response indicates an error
def
_getlongresp
(
self
):
resp
=
self
.
_getresp
()
list
=
[]
while
1
:
line
=
self
.
_getline
()
if
line
==
'.'
:
break
list
=
[];
octets
=
0
line
,
o
=
self
.
_getline
()
while
line
!=
'.'
:
octets
=
octets
+
o
list
.
append
(
line
)
return
resp
,
list
line
,
o
=
self
.
_getline
()
return
resp
,
list
,
octets
# Internal: send a command and get the response
def
_shortcmd
(
self
,
line
):
self
.
_putcmd
(
line
)
return
self
.
_getresp
()
# Internal: send a command and get the response plus following text
def
_longcmd
(
self
,
line
):
self
.
_putcmd
(
line
)
return
self
.
_getlongresp
()
# These can be useful:
def
getwelcome
(
self
):
def
getwelcome
(
self
):
return
self
.
welcome
def
set_debuglevel
(
self
,
level
):
self
.
_debugging
=
level
# Here are all the POP commands:
def
user
(
self
,
user
):
user
=
str
(
user
)
return
self
.
_shortcmd
(
'USER '
+
user
)
"""Send user name, return response
(should indicate password required).
"""
return
self
.
_shortcmd
(
'USER %s'
%
user
)
def
pass_
(
self
,
pswd
):
pswd
=
str
(
pswd
)
return
self
.
_shortcmd
(
'PASS '
+
pswd
)
"""Send password, return response
(response includes message count, mailbox size).
NB: mailbox is locked by server from here to 'quit()'
"""
return
self
.
_shortcmd
(
'PASS %s'
%
pswd
)
def
stat
(
self
):
"""Get mailbox status.
Result is tuple of 2 ints (message count, mailbox size)
"""
retval
=
self
.
_shortcmd
(
'STAT'
)
rets
=
string
.
split
(
retval
)
#if self._debugging: print '*stat*', `rets`
numMessages
=
string
.
atoi
(
rets
[
1
])
sizeMessages
=
string
.
atoi
(
rets
[
2
])
return
(
numMessages
,
sizeMessages
)
def
list
(
self
,
msg
=
None
):
if
msg
:
msg
=
str
(
msg
)
return
self
.
_longcmd
(
'LIST '
+
msg
)
else
:
return
self
.
_longcmd
(
'LIST'
)
def
list
(
self
,
which
=
None
):
"""Request listing, return result.
Result is in form ['response', ['mesg_num octets', ...]].
Unsure what the optional 'msg' arg does.
"""
if
which
:
return
self
.
_longcmd
(
'LIST %s'
%
which
)
return
self
.
_longcmd
(
'LIST'
)
def
retr
(
self
,
which
):
which
=
str
(
which
)
return
self
.
_longcmd
(
'RETR '
+
which
)
"""Retrieve whole message number 'which'.
Result is in form ['response', ['line', ...], octets].
"""
return
self
.
_longcmd
(
'RETR %s'
%
which
)
def
dele
(
self
,
which
):
which
=
str
(
which
)
return
self
.
_shortcmd
(
'DELE '
+
which
)
"""Delete message number 'which'.
Result is 'response'.
"""
return
self
.
_shortcmd
(
'DELE %s'
%
which
)
def
noop
(
self
):
"""Does nothing.
One supposes the response indicates the server is alive.
"""
return
self
.
_shortcmd
(
'NOOP'
)
def
rset
(
self
):
"""Not sure what this does."""
return
self
.
_shortcmd
(
'RSET'
)
# optional commands:
def
apop
(
self
,
digest
):
digest
=
str
(
digest
)
return
self
.
_shortcmd
(
'APOP '
+
digest
)
def
top
(
self
,
which
,
howmuch
):
which
=
str
(
which
)
howmuch
=
str
(
howmuch
)
return
self
.
_longcmd
(
'TOP '
+
which
+
' '
+
howmuch
)
def
uidl
(
self
,
which
=
None
):
if
which
:
which
=
str
(
which
)
return
self
.
_longcmd
(
'UIDL '
+
which
)
else
:
return
self
.
_longcmd
(
'UIDL'
)
def
quit
(
self
):
resp
=
self
.
_shortcmd
(
'QUIT'
)
"""Signoff: commit changes on server, unlock mailbox, close connection."""
try
:
resp
=
self
.
_shortcmd
(
'QUIT'
)
except
error_proto
(
val
):
resp
=
val
self
.
file
.
close
()
self
.
sock
.
close
()
del
self
.
file
,
self
.
sock
return
resp
#__del__ = quit
# optional commands:
def
rpop
(
self
,
user
):
"""Not sure what this does."""
return
self
.
_shortcmd
(
'RPOP %s'
%
user
)
timestamp
=
regex
.
compile
(
'
\
+OK.*
\
(<[^>]+>
\
)
'
)
def apop(self, user, secret):
"""Authorisation
- only possible if server has supplied a timestamp in initial greeting.
Args:
user - mailbox user;
secret - secret shared between client and server.
NB: mailbox is locked by server from here to '
quit
()
'
"""
if self.timestamp.match(self.welcome) <= 0:
raise error_proto('
-
ERR
APOP
not
supported
by
server
')
import md5
digest = md5.new(self.timestamp.group(1)+secret).digest()
digest = string.join(map(lambda x:'
%
02
x
'%ord(x), digest), '')
return self._shortcmd('
APOP
%
s
%
s
' % (user, digest))
def top(self, which, howmuch):
"""Retrieve message header of message number '
which
'
and first '
howmuch
' lines of message body.
Result is in form ['
response
', ['
line
', ...], octets].
"""
return self._longcmd('
TOP
%
s
%
s
' % (which, howmuch))
def uidl(self, which=None):
"""Return message digest (unique id) list.
If '
which
', result contains unique id for that message,
otherwise result is list ['
response
', ['
mesgnum
uid
', ...], octets]
"""
if which:
return self._shortcmd('
UIDL
%
s
' % which)
return self._longcmd('
UIDL
')
if __name__ == "__main__":
a = POP3(TESTSERVER)
print a.getwelcome()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment