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
463a4d72
Commit
463a4d72
authored
Jan 14, 2001
by
Tim Peters
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Whitespace normalization.
parent
93fd3db8
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
1991 additions
and
1994 deletions
+1991
-1994
Lib/MimeWriter.py
Lib/MimeWriter.py
+1
-1
Lib/getpass.py
Lib/getpass.py
+75
-76
Lib/gettext.py
Lib/gettext.py
+7
-7
Lib/glob.py
Lib/glob.py
+41
-41
Lib/gzip.py
Lib/gzip.py
+25
-25
Lib/htmlentitydefs.py
Lib/htmlentitydefs.py
+252
-252
Lib/htmllib.py
Lib/htmllib.py
+1
-1
Lib/httplib.py
Lib/httplib.py
+17
-17
Lib/ihooks.py
Lib/ihooks.py
+2
-2
Lib/imaplib.py
Lib/imaplib.py
+818
-819
Lib/imghdr.py
Lib/imghdr.py
+2
-2
Lib/imputil.py
Lib/imputil.py
+6
-6
Lib/macurl2path.py
Lib/macurl2path.py
+5
-5
Lib/mailcap.py
Lib/mailcap.py
+3
-3
Lib/mimetools.py
Lib/mimetools.py
+176
-176
Lib/mimify.py
Lib/mimify.py
+398
-399
Lib/multifile.py
Lib/multifile.py
+130
-130
Lib/mutex.py
Lib/mutex.py
+32
-32
No files found.
Lib/MimeWriter.py
View file @
463a4d72
...
...
@@ -30,7 +30,7 @@ class MimeWriter:
amounts of buffer space, so you have to write the parts in the
order they should occur on the output file. It does buffer the
headers you add, allowing you to rearrange their order.
General usage is:
f = <open the output file>
...
...
Lib/getpass.py
View file @
463a4d72
...
...
@@ -14,106 +14,105 @@ On the Mac EasyDialogs.AskPassword is used, if available.
import
sys
def
unix_getpass
(
prompt
=
'Password: '
):
"""Prompt for a password, with echo turned off.
"""Prompt for a password, with echo turned off.
Restore terminal settings at end.
"""
Restore terminal settings at end.
"""
try
:
fd
=
sys
.
stdin
.
fileno
()
except
:
return
default_getpass
(
prompt
)
try
:
fd
=
sys
.
stdin
.
fileno
()
except
:
return
default_getpass
(
prompt
)
getpass
=
default_getpass
old
=
termios
.
tcgetattr
(
fd
)
# a copy to save
new
=
old
[:]
getpass
=
default_getpass
old
=
termios
.
tcgetattr
(
fd
)
# a copy to save
new
=
old
[:]
new
[
3
]
=
new
[
3
]
&
~
TERMIOS
.
ECHO
# 3 == 'lflags'
try
:
termios
.
tcsetattr
(
fd
,
TERMIOS
.
TCSADRAIN
,
new
)
passwd
=
_raw_input
(
prompt
)
finally
:
termios
.
tcsetattr
(
fd
,
TERMIOS
.
TCSADRAIN
,
old
)
new
[
3
]
=
new
[
3
]
&
~
TERMIOS
.
ECHO
# 3 == 'lflags'
try
:
termios
.
tcsetattr
(
fd
,
TERMIOS
.
TCSADRAIN
,
new
)
passwd
=
_raw_input
(
prompt
)
finally
:
termios
.
tcsetattr
(
fd
,
TERMIOS
.
TCSADRAIN
,
old
)
sys
.
stdout
.
write
(
'
\
n
'
)
return
passwd
sys
.
stdout
.
write
(
'
\
n
'
)
return
passwd
def
win_getpass
(
prompt
=
'Password: '
):
"""Prompt for password with echo off, using Windows getch()."""
import
msvcrt
for
c
in
prompt
:
msvcrt
.
putch
(
c
)
pw
=
""
while
1
:
c
=
msvcrt
.
getch
()
if
c
==
'
\
r
'
or
c
==
'
\
n
'
:
break
if
c
==
'
\
003
'
:
raise
KeyboardInterrupt
if
c
==
'
\
b
'
:
pw
=
pw
[:
-
1
]
else
:
pw
=
pw
+
c
msvcrt
.
putch
(
'
\
r
'
)
msvcrt
.
putch
(
'
\
n
'
)
return
pw
"""Prompt for password with echo off, using Windows getch()."""
import
msvcrt
for
c
in
prompt
:
msvcrt
.
putch
(
c
)
pw
=
""
while
1
:
c
=
msvcrt
.
getch
()
if
c
==
'
\
r
'
or
c
==
'
\
n
'
:
break
if
c
==
'
\
003
'
:
raise
KeyboardInterrupt
if
c
==
'
\
b
'
:
pw
=
pw
[:
-
1
]
else
:
pw
=
pw
+
c
msvcrt
.
putch
(
'
\
r
'
)
msvcrt
.
putch
(
'
\
n
'
)
return
pw
def
default_getpass
(
prompt
=
'Password: '
):
print
"Warning: Problem with getpass. Passwords may be echoed."
return
_raw_input
(
prompt
)
print
"Warning: Problem with getpass. Passwords may be echoed."
return
_raw_input
(
prompt
)
def
_raw_input
(
prompt
=
""
):
# A raw_input() replacement that doesn't save the string in the
# GNU readline history.
import
sys
prompt
=
str
(
prompt
)
if
prompt
:
sys
.
stdout
.
write
(
prompt
)
line
=
sys
.
stdin
.
readline
()
if
not
line
:
raise
EOFError
if
line
[
-
1
]
==
'
\
n
'
:
line
=
line
[:
-
1
]
return
line
# A raw_input() replacement that doesn't save the string in the
# GNU readline history.
import
sys
prompt
=
str
(
prompt
)
if
prompt
:
sys
.
stdout
.
write
(
prompt
)
line
=
sys
.
stdin
.
readline
()
if
not
line
:
raise
EOFError
if
line
[
-
1
]
==
'
\
n
'
:
line
=
line
[:
-
1
]
return
line
def
getuser
():
"""Get the username from the environment or password database.
"""Get the username from the environment or password database.
First try various environment variables, then the password
database. This works on Windows as long as USERNAME is set.
First try various environment variables, then the password
database. This works on Windows as long as USERNAME is set.
"""
"""
import
os
import
os
for
name
in
(
'LOGNAME'
,
'USER'
,
'LNAME'
,
'USERNAME'
):
user
=
os
.
environ
.
get
(
name
)
if
user
:
return
user
for
name
in
(
'LOGNAME'
,
'USER'
,
'LNAME'
,
'USERNAME'
):
user
=
os
.
environ
.
get
(
name
)
if
user
:
return
user
# If this fails, the exception will "explain" why
import
pwd
return
pwd
.
getpwuid
(
os
.
getuid
())[
0
]
# If this fails, the exception will "explain" why
import
pwd
return
pwd
.
getpwuid
(
os
.
getuid
())[
0
]
# Bind the name getpass to the appropriate function
try
:
import
termios
,
TERMIOS
import
termios
,
TERMIOS
except
ImportError
:
try
:
import
msvcrt
except
ImportError
:
try
:
from
EasyDialogs
import
AskPassword
except
ImportError
:
getpass
=
default_getpass
else
:
getpass
=
AskPassword
else
:
getpass
=
win_getpass
try
:
import
msvcrt
except
ImportError
:
try
:
from
EasyDialogs
import
AskPassword
except
ImportError
:
getpass
=
default_getpass
else
:
getpass
=
AskPassword
else
:
getpass
=
win_getpass
else
:
getpass
=
unix_getpass
getpass
=
unix_getpass
Lib/gettext.py
View file @
463a4d72
...
...
@@ -51,7 +51,7 @@ from errno import ENOENT
_default_localedir
=
os
.
path
.
join
(
sys
.
prefix
,
'share'
,
'locale'
)
def
_expand_lang
(
locale
):
from
locale
import
normalize
locale
=
normalize
(
locale
)
...
...
@@ -94,7 +94,7 @@ def _expand_lang(locale):
return
ret
class
NullTranslations
:
def
__init__
(
self
,
fp
=
None
):
self
.
_info
=
{}
...
...
@@ -192,7 +192,7 @@ class GNUTranslations(NullTranslations):
return
unicode
(
tmsg
,
self
.
_charset
)
# Locate a .mo file using the gettext strategy
def
find
(
domain
,
localedir
=
None
,
languages
=
None
):
# Get some reasonable defaults for arguments that were not supplied
...
...
@@ -223,7 +223,7 @@ def find(domain, localedir=None, languages=None):
return
None
# a mapping between absolute .mo file path and Translation object
_translations
=
{}
...
...
@@ -243,12 +243,12 @@ def translation(domain, localedir=None, languages=None, class_=None):
return
t
def
install
(
domain
,
localedir
=
None
,
unicode
=
0
):
translation
(
domain
,
localedir
).
install
(
unicode
)
# a mapping b/w domains and locale directories
_localedirs
=
{}
# current global domain, `messages' used for compatibility w/ GNU gettext
...
...
@@ -275,7 +275,7 @@ def dgettext(domain, message):
except
IOError
:
return
message
return
t
.
gettext
(
message
)
def
gettext
(
message
):
return
dgettext
(
_current_domain
,
message
)
...
...
Lib/glob.py
View file @
463a4d72
...
...
@@ -6,51 +6,51 @@ import re
def
glob
(
pathname
):
"""Return a list of paths matching a pathname pattern.
The pattern may contain simple shell-style wildcards a la fnmatch.
"""
if
not
has_magic
(
pathname
):
if
os
.
path
.
exists
(
pathname
):
return
[
pathname
]
else
:
return
[]
dirname
,
basename
=
os
.
path
.
split
(
pathname
)
if
has_magic
(
dirname
):
list
=
glob
(
dirname
)
else
:
list
=
[
dirname
]
if
not
has_magic
(
basename
):
result
=
[]
for
dirname
in
list
:
if
basename
or
os
.
path
.
isdir
(
dirname
):
name
=
os
.
path
.
join
(
dirname
,
basename
)
if
os
.
path
.
exists
(
name
):
result
.
append
(
name
)
else
:
result
=
[]
for
dirname
in
list
:
sublist
=
glob1
(
dirname
,
basename
)
for
name
in
sublist
:
result
.
append
(
os
.
path
.
join
(
dirname
,
name
))
return
result
"""Return a list of paths matching a pathname pattern.
The pattern may contain simple shell-style wildcards a la fnmatch.
"""
if
not
has_magic
(
pathname
):
if
os
.
path
.
exists
(
pathname
):
return
[
pathname
]
else
:
return
[]
dirname
,
basename
=
os
.
path
.
split
(
pathname
)
if
has_magic
(
dirname
):
list
=
glob
(
dirname
)
else
:
list
=
[
dirname
]
if
not
has_magic
(
basename
):
result
=
[]
for
dirname
in
list
:
if
basename
or
os
.
path
.
isdir
(
dirname
):
name
=
os
.
path
.
join
(
dirname
,
basename
)
if
os
.
path
.
exists
(
name
):
result
.
append
(
name
)
else
:
result
=
[]
for
dirname
in
list
:
sublist
=
glob1
(
dirname
,
basename
)
for
name
in
sublist
:
result
.
append
(
os
.
path
.
join
(
dirname
,
name
))
return
result
def
glob1
(
dirname
,
pattern
):
if
not
dirname
:
dirname
=
os
.
curdir
try
:
names
=
os
.
listdir
(
dirname
)
except
os
.
error
:
return
[]
result
=
[]
for
name
in
names
:
if
name
[
0
]
!=
'.'
or
pattern
[
0
]
==
'.'
:
if
fnmatch
.
fnmatch
(
name
,
pattern
):
result
.
append
(
name
)
return
result
if
not
dirname
:
dirname
=
os
.
curdir
try
:
names
=
os
.
listdir
(
dirname
)
except
os
.
error
:
return
[]
result
=
[]
for
name
in
names
:
if
name
[
0
]
!=
'.'
or
pattern
[
0
]
==
'.'
:
if
fnmatch
.
fnmatch
(
name
,
pattern
):
result
.
append
(
name
)
return
result
magic_check
=
re
.
compile
(
'[*?[]'
)
def
has_magic
(
s
):
return
magic_check
.
search
(
s
)
is
not
None
return
magic_check
.
search
(
s
)
is
not
None
Lib/gzip.py
View file @
463a4d72
...
...
@@ -15,7 +15,7 @@ READ, WRITE = 1, 2
def
write32
(
output
,
value
):
output
.
write
(
struct
.
pack
(
"<l"
,
value
))
def
write32u
(
output
,
value
):
output
.
write
(
struct
.
pack
(
"<L"
,
value
))
...
...
@@ -29,7 +29,7 @@ class GzipFile:
myfileobj
=
None
def
__init__
(
self
,
filename
=
None
,
mode
=
None
,
def
__init__
(
self
,
filename
=
None
,
mode
=
None
,
compresslevel
=
9
,
fileobj
=
None
):
if
fileobj
is
None
:
fileobj
=
self
.
myfileobj
=
__builtin__
.
open
(
filename
,
mode
or
'rb'
)
...
...
@@ -42,8 +42,8 @@ class GzipFile:
if
mode
[
0
:
1
]
==
'r'
:
self
.
mode
=
READ
# Set flag indicating start of a new member
self
.
_new_member
=
1
# Set flag indicating start of a new member
self
.
_new_member
=
1
self
.
extrabuf
=
""
self
.
extrasize
=
0
self
.
filename
=
filename
...
...
@@ -52,7 +52,7 @@ class GzipFile:
self
.
mode
=
WRITE
self
.
_init_write
(
filename
)
self
.
compress
=
zlib
.
compressobj
(
compresslevel
,
zlib
.
DEFLATED
,
zlib
.
DEFLATED
,
-
zlib
.
MAX_WBITS
,
zlib
.
DEF_MEM_LEVEL
,
0
)
...
...
@@ -110,7 +110,7 @@ class GzipFile:
if
flag
&
FEXTRA
:
# Read & discard the extra field, if present
xlen
=
ord
(
self
.
fileobj
.
read
(
1
))
xlen
=
ord
(
self
.
fileobj
.
read
(
1
))
xlen
=
xlen
+
256
*
ord
(
self
.
fileobj
.
read
(
1
))
self
.
fileobj
.
read
(
xlen
)
if
flag
&
FNAME
:
...
...
@@ -158,7 +158,7 @@ class GzipFile:
except
EOFError
:
if
size
>
self
.
extrasize
:
size
=
self
.
extrasize
chunk
=
self
.
extrabuf
[:
size
]
self
.
extrabuf
=
self
.
extrabuf
[
size
:]
self
.
extrasize
=
self
.
extrasize
-
size
...
...
@@ -171,11 +171,11 @@ class GzipFile:
def
_read
(
self
,
size
=
1024
):
if
self
.
fileobj
is
None
:
raise
EOFError
,
"Reached EOF"
if
self
.
_new_member
:
# If the _new_member flag is set, we have to
# jump to the next member, if there is one.
#
#
# First, check if we're at the end of the file;
# if so, it's time to stop; no more members to read.
pos
=
self
.
fileobj
.
tell
()
# Save current position
...
...
@@ -183,27 +183,27 @@ class GzipFile:
if
pos
==
self
.
fileobj
.
tell
():
self
.
fileobj
=
None
raise
EOFError
,
"Reached EOF"
else
:
else
:
self
.
fileobj
.
seek
(
pos
)
# Return to original position
self
.
_init_read
()
self
.
_init_read
()
self
.
_read_gzip_header
()
self
.
decompress
=
zlib
.
decompressobj
(
-
zlib
.
MAX_WBITS
)
self
.
_new_member
=
0
# Read a chunk of data from the file
buf
=
self
.
fileobj
.
read
(
size
)
# If the EOF has been reached, flush the decompression object
# and mark this object as finished.
if
buf
==
""
:
uncompress
=
self
.
decompress
.
flush
()
self
.
_read_eof
()
self
.
fileobj
=
None
self
.
_add_read_data
(
uncompress
)
raise
EOFError
,
'Reached EOF'
uncompress
=
self
.
decompress
.
decompress
(
buf
)
self
.
_add_read_data
(
uncompress
)
...
...
@@ -216,11 +216,11 @@ class GzipFile:
self
.
fileobj
.
seek
(
-
len
(
self
.
decompress
.
unused_data
)
+
8
,
1
)
# Check the CRC and file size, and set the flag so we read
# a new member on the next call
# a new member on the next call
self
.
_read_eof
()
self
.
_new_member
=
1
def
_add_read_data
(
self
,
data
):
self
.
_new_member
=
1
def
_add_read_data
(
self
,
data
):
self
.
crc
=
zlib
.
crc32
(
data
,
self
.
crc
)
self
.
extrabuf
=
self
.
extrabuf
+
data
self
.
extrasize
=
self
.
extrasize
+
len
(
data
)
...
...
@@ -228,7 +228,7 @@ class GzipFile:
def
_read_eof
(
self
):
# We've read to the end of the file, so we have to rewind in order
# to reread the 8 bytes containing the CRC and the file size.
# to reread the 8 bytes containing the CRC and the file size.
# We check the that the computed CRC and size of the
# uncompressed data matches the stored values.
self
.
fileobj
.
seek
(
-
8
,
1
)
...
...
@@ -238,7 +238,7 @@ class GzipFile:
raise
ValueError
,
"CRC check failed"
elif
isize
!=
self
.
size
:
raise
ValueError
,
"Incorrect length of data produced"
def
close
(
self
):
if
self
.
mode
==
WRITE
:
self
.
fileobj
.
write
(
self
.
compress
.
flush
())
...
...
@@ -259,7 +259,7 @@ class GzipFile:
except
AttributeError
:
return
self
.
close
()
def
flush
(
self
):
self
.
fileobj
.
flush
()
...
...
@@ -285,7 +285,7 @@ class GzipFile:
i
=
string
.
find
(
c
,
'
\
n
'
)
if
size
is
not
None
:
# We set i=size to break out of the loop under two
# conditions: 1) there's no newline, and the chunk is
# conditions: 1) there's no newline, and the chunk is
# larger than size, or 2) there is a newline, but the
# resulting line would be longer than 'size'.
if
i
==-
1
and
len
(
c
)
>
size
:
i
=
size
-
1
...
...
@@ -300,7 +300,7 @@ class GzipFile:
bufs
.
append
(
c
)
size
=
size
-
len
(
c
)
readsize
=
min
(
size
,
readsize
*
2
)
def
readlines
(
self
,
sizehint
=
0
):
# Negative numbers result in reading all the lines
if
sizehint
<=
0
:
sizehint
=
sys
.
maxint
...
...
Lib/htmlentitydefs.py
View file @
463a4d72
"""HTML character entity references."""
entitydefs
=
{
'AElig'
:
'
\
306
'
,
# latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1
'Aacute'
:
'
\
301
'
,
# latin capital letter A with acute, U+00C1 ISOlat1
'Acirc'
:
'
\
302
'
,
# latin capital letter A with circumflex, U+00C2 ISOlat1
'Agrave'
:
'
\
300
'
,
# latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1
'Alpha'
:
'Α'
,
# greek capital letter alpha, U+0391
'Aring'
:
'
\
305
'
,
# latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1
'Atilde'
:
'
\
303
'
,
# latin capital letter A with tilde, U+00C3 ISOlat1
'Auml'
:
'
\
304
'
,
# latin capital letter A with diaeresis, U+00C4 ISOlat1
'Beta'
:
'Β'
,
# greek capital letter beta, U+0392
'Ccedil'
:
'
\
307
'
,
# latin capital letter C with cedilla, U+00C7 ISOlat1
'Chi'
:
'Χ'
,
# greek capital letter chi, U+03A7
'Dagger'
:
'‡'
,
# double dagger, U+2021 ISOpub
'Delta'
:
'Δ'
,
# greek capital letter delta, U+0394 ISOgrk3
'ETH'
:
'
\
320
'
,
# latin capital letter ETH, U+00D0 ISOlat1
'Eacute'
:
'
\
311
'
,
# latin capital letter E with acute, U+00C9 ISOlat1
'Ecirc'
:
'
\
312
'
,
# latin capital letter E with circumflex, U+00CA ISOlat1
'Egrave'
:
'
\
310
'
,
# latin capital letter E with grave, U+00C8 ISOlat1
'Epsilon'
:
'Ε'
,
# greek capital letter epsilon, U+0395
'Eta'
:
'Η'
,
# greek capital letter eta, U+0397
'Euml'
:
'
\
313
'
,
# latin capital letter E with diaeresis, U+00CB ISOlat1
'Gamma'
:
'Γ'
,
# greek capital letter gamma, U+0393 ISOgrk3
'Iacute'
:
'
\
315
'
,
# latin capital letter I with acute, U+00CD ISOlat1
'Icirc'
:
'
\
316
'
,
# latin capital letter I with circumflex, U+00CE ISOlat1
'Igrave'
:
'
\
314
'
,
# latin capital letter I with grave, U+00CC ISOlat1
'Iota'
:
'Ι'
,
# greek capital letter iota, U+0399
'Iuml'
:
'
\
317
'
,
# latin capital letter I with diaeresis, U+00CF ISOlat1
'Kappa'
:
'Κ'
,
# greek capital letter kappa, U+039A
'Lambda'
:
'Λ'
,
# greek capital letter lambda, U+039B ISOgrk3
'Mu'
:
'Μ'
,
# greek capital letter mu, U+039C
'Ntilde'
:
'
\
321
'
,
# latin capital letter N with tilde, U+00D1 ISOlat1
'Nu'
:
'Ν'
,
# greek capital letter nu, U+039D
'OElig'
:
'Œ'
,
# latin capital ligature OE, U+0152 ISOlat2
'Oacute'
:
'
\
323
'
,
# latin capital letter O with acute, U+00D3 ISOlat1
'Ocirc'
:
'
\
324
'
,
# latin capital letter O with circumflex, U+00D4 ISOlat1
'Ograve'
:
'
\
322
'
,
# latin capital letter O with grave, U+00D2 ISOlat1
'Omega'
:
'Ω'
,
# greek capital letter omega, U+03A9 ISOgrk3
'Omicron'
:
'Ο'
,
# greek capital letter omicron, U+039F
'Oslash'
:
'
\
330
'
,
# latin capital letter O with stroke = latin capital letter O slash, U+00D8 ISOlat1
'Otilde'
:
'
\
325
'
,
# latin capital letter O with tilde, U+00D5 ISOlat1
'Ouml'
:
'
\
326
'
,
# latin capital letter O with diaeresis, U+00D6 ISOlat1
'Phi'
:
'Φ'
,
# greek capital letter phi, U+03A6 ISOgrk3
'Pi'
:
'Π'
,
# greek capital letter pi, U+03A0 ISOgrk3
'Prime'
:
'″'
,
# double prime = seconds = inches, U+2033 ISOtech
'Psi'
:
'Ψ'
,
# greek capital letter psi, U+03A8 ISOgrk3
'Rho'
:
'Ρ'
,
# greek capital letter rho, U+03A1
'Scaron'
:
'Š'
,
# latin capital letter S with caron, U+0160 ISOlat2
'Sigma'
:
'Σ'
,
# greek capital letter sigma, U+03A3 ISOgrk3
'THORN'
:
'
\
336
'
,
# latin capital letter THORN, U+00DE ISOlat1
'Tau'
:
'Τ'
,
# greek capital letter tau, U+03A4
'Theta'
:
'Θ'
,
# greek capital letter theta, U+0398 ISOgrk3
'Uacute'
:
'
\
332
'
,
# latin capital letter U with acute, U+00DA ISOlat1
'Ucirc'
:
'
\
333
'
,
# latin capital letter U with circumflex, U+00DB ISOlat1
'Ugrave'
:
'
\
331
'
,
# latin capital letter U with grave, U+00D9 ISOlat1
'Upsilon'
:
'Υ'
,
# greek capital letter upsilon, U+03A5 ISOgrk3
'Uuml'
:
'
\
334
'
,
# latin capital letter U with diaeresis, U+00DC ISOlat1
'Xi'
:
'Ξ'
,
# greek capital letter xi, U+039E ISOgrk3
'Yacute'
:
'
\
335
'
,
# latin capital letter Y with acute, U+00DD ISOlat1
'Yuml'
:
'Ÿ'
,
# latin capital letter Y with diaeresis, U+0178 ISOlat2
'Zeta'
:
'Ζ'
,
# greek capital letter zeta, U+0396
'aacute'
:
'
\
341
'
,
# latin small letter a with acute, U+00E1 ISOlat1
'acirc'
:
'
\
342
'
,
# latin small letter a with circumflex, U+00E2 ISOlat1
'acute'
:
'
\
264
'
,
# acute accent = spacing acute, U+00B4 ISOdia
'aelig'
:
'
\
346
'
,
# latin small letter ae = latin small ligature ae, U+00E6 ISOlat1
'agrave'
:
'
\
340
'
,
# latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1
'alefsym'
:
'ℵ'
,
# alef symbol = first transfinite cardinal, U+2135 NEW
'alpha'
:
'α'
,
# greek small letter alpha, U+03B1 ISOgrk3
'amp'
:
'
\
46
'
,
# ampersand, U+0026 ISOnum
'and'
:
'∧'
,
# logical and = wedge, U+2227 ISOtech
'ang'
:
'∠'
,
# angle, U+2220 ISOamso
'aring'
:
'
\
345
'
,
# latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1
'asymp'
:
'≈'
,
# almost equal to = asymptotic to, U+2248 ISOamsr
'atilde'
:
'
\
343
'
,
# latin small letter a with tilde, U+00E3 ISOlat1
'auml'
:
'
\
344
'
,
# latin small letter a with diaeresis, U+00E4 ISOlat1
'bdquo'
:
'„'
,
# double low-9 quotation mark, U+201E NEW
'beta'
:
'β'
,
# greek small letter beta, U+03B2 ISOgrk3
'brvbar'
:
'
\
246
'
,
# broken bar = broken vertical bar, U+00A6 ISOnum
'bull'
:
'•'
,
# bullet = black small circle, U+2022 ISOpub
'cap'
:
'∩'
,
# intersection = cap, U+2229 ISOtech
'ccedil'
:
'
\
347
'
,
# latin small letter c with cedilla, U+00E7 ISOlat1
'cedil'
:
'
\
270
'
,
# cedilla = spacing cedilla, U+00B8 ISOdia
'cent'
:
'
\
242
'
,
# cent sign, U+00A2 ISOnum
'chi'
:
'χ'
,
# greek small letter chi, U+03C7 ISOgrk3
'circ'
:
'ˆ'
,
# modifier letter circumflex accent, U+02C6 ISOpub
'clubs'
:
'♣'
,
# black club suit = shamrock, U+2663 ISOpub
'cong'
:
'≅'
,
# approximately equal to, U+2245 ISOtech
'copy'
:
'
\
251
'
,
# copyright sign, U+00A9 ISOnum
'crarr'
:
'↵'
,
# downwards arrow with corner leftwards = carriage return, U+21B5 NEW
'cup'
:
'∪'
,
# union = cup, U+222A ISOtech
'curren'
:
'
\
244
'
,
# currency sign, U+00A4 ISOnum
'dArr'
:
'⇓'
,
# downwards double arrow, U+21D3 ISOamsa
'dagger'
:
'†'
,
# dagger, U+2020 ISOpub
'darr'
:
'↓'
,
# downwards arrow, U+2193 ISOnum
'deg'
:
'
\
260
'
,
# degree sign, U+00B0 ISOnum
'delta'
:
'δ'
,
# greek small letter delta, U+03B4 ISOgrk3
'diams'
:
'♦'
,
# black diamond suit, U+2666 ISOpub
'divide'
:
'
\
367
'
,
# division sign, U+00F7 ISOnum
'eacute'
:
'
\
351
'
,
# latin small letter e with acute, U+00E9 ISOlat1
'ecirc'
:
'
\
352
'
,
# latin small letter e with circumflex, U+00EA ISOlat1
'egrave'
:
'
\
350
'
,
# latin small letter e with grave, U+00E8 ISOlat1
'empty'
:
'∅'
,
# empty set = null set = diameter, U+2205 ISOamso
'emsp'
:
' '
,
# em space, U+2003 ISOpub
'ensp'
:
' '
,
# en space, U+2002 ISOpub
'epsilon'
:
'ε'
,
# greek small letter epsilon, U+03B5 ISOgrk3
'equiv'
:
'≡'
,
# identical to, U+2261 ISOtech
'eta'
:
'η'
,
# greek small letter eta, U+03B7 ISOgrk3
'eth'
:
'
\
360
'
,
# latin small letter eth, U+00F0 ISOlat1
'euml'
:
'
\
353
'
,
# latin small letter e with diaeresis, U+00EB ISOlat1
'euro'
:
'€'
,
# euro sign, U+20AC NEW
'exist'
:
'∃'
,
# there exists, U+2203 ISOtech
'fnof'
:
'ƒ'
,
# latin small f with hook = function = florin, U+0192 ISOtech
'forall'
:
'∀'
,
# for all, U+2200 ISOtech
'frac12'
:
'
\
275
'
,
# vulgar fraction one half = fraction one half, U+00BD ISOnum
'frac14'
:
'
\
274
'
,
# vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum
'frac34'
:
'
\
276
'
,
# vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum
'frasl'
:
'⁄'
,
# fraction slash, U+2044 NEW
'gamma'
:
'γ'
,
# greek small letter gamma, U+03B3 ISOgrk3
'ge'
:
'≥'
,
# greater-than or equal to, U+2265 ISOtech
'gt'
:
'
\
76
'
,
# greater-than sign, U+003E ISOnum
'hArr'
:
'⇔'
,
# left right double arrow, U+21D4 ISOamsa
'harr'
:
'↔'
,
# left right arrow, U+2194 ISOamsa
'hearts'
:
'♥'
,
# black heart suit = valentine, U+2665 ISOpub
'hellip'
:
'…'
,
# horizontal ellipsis = three dot leader, U+2026 ISOpub
'iacute'
:
'
\
355
'
,
# latin small letter i with acute, U+00ED ISOlat1
'icirc'
:
'
\
356
'
,
# latin small letter i with circumflex, U+00EE ISOlat1
'iexcl'
:
'
\
241
'
,
# inverted exclamation mark, U+00A1 ISOnum
'igrave'
:
'
\
354
'
,
# latin small letter i with grave, U+00EC ISOlat1
'image'
:
'ℑ'
,
# blackletter capital I = imaginary part, U+2111 ISOamso
'infin'
:
'∞'
,
# infinity, U+221E ISOtech
'int'
:
'∫'
,
# integral, U+222B ISOtech
'iota'
:
'ι'
,
# greek small letter iota, U+03B9 ISOgrk3
'iquest'
:
'
\
277
'
,
# inverted question mark = turned question mark, U+00BF ISOnum
'isin'
:
'∈'
,
# element of, U+2208 ISOtech
'iuml'
:
'
\
357
'
,
# latin small letter i with diaeresis, U+00EF ISOlat1
'kappa'
:
'κ'
,
# greek small letter kappa, U+03BA ISOgrk3
'lArr'
:
'⇐'
,
# leftwards double arrow, U+21D0 ISOtech
'lambda'
:
'λ'
,
# greek small letter lambda, U+03BB ISOgrk3
'lang'
:
'〈'
,
# left-pointing angle bracket = bra, U+2329 ISOtech
'laquo'
:
'
\
253
'
,
# left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum
'larr'
:
'←'
,
# leftwards arrow, U+2190 ISOnum
'lceil'
:
'⌈'
,
# left ceiling = apl upstile, U+2308 ISOamsc
'ldquo'
:
'“'
,
# left double quotation mark, U+201C ISOnum
'le'
:
'≤'
,
# less-than or equal to, U+2264 ISOtech
'lfloor'
:
'⌊'
,
# left floor = apl downstile, U+230A ISOamsc
'lowast'
:
'∗'
,
# asterisk operator, U+2217 ISOtech
'loz'
:
'◊'
,
# lozenge, U+25CA ISOpub
'lrm'
:
'‎'
,
# left-to-right mark, U+200E NEW RFC 2070
'lsaquo'
:
'‹'
,
# single left-pointing angle quotation mark, U+2039 ISO proposed
'lsquo'
:
'‘'
,
# left single quotation mark, U+2018 ISOnum
'lt'
:
'
\
74
'
,
# less-than sign, U+003C ISOnum
'macr'
:
'
\
257
'
,
# macron = spacing macron = overline = APL overbar, U+00AF ISOdia
'mdash'
:
'—'
,
# em dash, U+2014 ISOpub
'micro'
:
'
\
265
'
,
# micro sign, U+00B5 ISOnum
'middot'
:
'
\
267
'
,
# middle dot = Georgian comma = Greek middle dot, U+00B7 ISOnum
'minus'
:
'−'
,
# minus sign, U+2212 ISOtech
'mu'
:
'μ'
,
# greek small letter mu, U+03BC ISOgrk3
'nabla'
:
'∇'
,
# nabla = backward difference, U+2207 ISOtech
'nbsp'
:
'
\
240
'
,
# no-break space = non-breaking space, U+00A0 ISOnum
'ndash'
:
'–'
,
# en dash, U+2013 ISOpub
'ne'
:
'≠'
,
# not equal to, U+2260 ISOtech
'ni'
:
'∋'
,
# contains as member, U+220B ISOtech
'not'
:
'
\
254
'
,
# not sign, U+00AC ISOnum
'notin'
:
'∉'
,
# not an element of, U+2209 ISOtech
'nsub'
:
'⊄'
,
# not a subset of, U+2284 ISOamsn
'ntilde'
:
'
\
361
'
,
# latin small letter n with tilde, U+00F1 ISOlat1
'nu'
:
'ν'
,
# greek small letter nu, U+03BD ISOgrk3
'oacute'
:
'
\
363
'
,
# latin small letter o with acute, U+00F3 ISOlat1
'ocirc'
:
'
\
364
'
,
# latin small letter o with circumflex, U+00F4 ISOlat1
'oelig'
:
'œ'
,
# latin small ligature oe, U+0153 ISOlat2
'ograve'
:
'
\
362
'
,
# latin small letter o with grave, U+00F2 ISOlat1
'oline'
:
'‾'
,
# overline = spacing overscore, U+203E NEW
'omega'
:
'ω'
,
# greek small letter omega, U+03C9 ISOgrk3
'omicron'
:
'ο'
,
# greek small letter omicron, U+03BF NEW
'oplus'
:
'⊕'
,
# circled plus = direct sum, U+2295 ISOamsb
'or'
:
'∨'
,
# logical or = vee, U+2228 ISOtech
'ordf'
:
'
\
252
'
,
# feminine ordinal indicator, U+00AA ISOnum
'ordm'
:
'
\
272
'
,
# masculine ordinal indicator, U+00BA ISOnum
'oslash'
:
'
\
370
'
,
# latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1
'otilde'
:
'
\
365
'
,
# latin small letter o with tilde, U+00F5 ISOlat1
'otimes'
:
'⊗'
,
# circled times = vector product, U+2297 ISOamsb
'ouml'
:
'
\
366
'
,
# latin small letter o with diaeresis, U+00F6 ISOlat1
'para'
:
'
\
266
'
,
# pilcrow sign = paragraph sign, U+00B6 ISOnum
'part'
:
'∂'
,
# partial differential, U+2202 ISOtech
'permil'
:
'‰'
,
# per mille sign, U+2030 ISOtech
'perp'
:
'⊥'
,
# up tack = orthogonal to = perpendicular, U+22A5 ISOtech
'phi'
:
'φ'
,
# greek small letter phi, U+03C6 ISOgrk3
'pi'
:
'π'
,
# greek small letter pi, U+03C0 ISOgrk3
'piv'
:
'ϖ'
,
# greek pi symbol, U+03D6 ISOgrk3
'plusmn'
:
'
\
261
'
,
# plus-minus sign = plus-or-minus sign, U+00B1 ISOnum
'pound'
:
'
\
243
'
,
# pound sign, U+00A3 ISOnum
'prime'
:
'′'
,
# prime = minutes = feet, U+2032 ISOtech
'prod'
:
'∏'
,
# n-ary product = product sign, U+220F ISOamsb
'prop'
:
'∝'
,
# proportional to, U+221D ISOtech
'psi'
:
'ψ'
,
# greek small letter psi, U+03C8 ISOgrk3
'quot'
:
'
\
42
'
,
# quotation mark = APL quote, U+0022 ISOnum
'rArr'
:
'⇒'
,
# rightwards double arrow, U+21D2 ISOtech
'radic'
:
'√'
,
# square root = radical sign, U+221A ISOtech
'rang'
:
'〉'
,
# right-pointing angle bracket = ket, U+232A ISOtech
'raquo'
:
'
\
273
'
,
# right-pointing double angle quotation mark = right pointing guillemet, U+00BB ISOnum
'rarr'
:
'→'
,
# rightwards arrow, U+2192 ISOnum
'rceil'
:
'⌉'
,
# right ceiling, U+2309 ISOamsc
'rdquo'
:
'”'
,
# right double quotation mark, U+201D ISOnum
'real'
:
'ℜ'
,
# blackletter capital R = real part symbol, U+211C ISOamso
'reg'
:
'
\
256
'
,
# registered sign = registered trade mark sign, U+00AE ISOnum
'rfloor'
:
'⌋'
,
# right floor, U+230B ISOamsc
'rho'
:
'ρ'
,
# greek small letter rho, U+03C1 ISOgrk3
'rlm'
:
'‏'
,
# right-to-left mark, U+200F NEW RFC 2070
'rsaquo'
:
'›'
,
# single right-pointing angle quotation mark, U+203A ISO proposed
'rsquo'
:
'’'
,
# right single quotation mark, U+2019 ISOnum
'sbquo'
:
'‚'
,
# single low-9 quotation mark, U+201A NEW
'scaron'
:
'š'
,
# latin small letter s with caron, U+0161 ISOlat2
'sdot'
:
'⋅'
,
# dot operator, U+22C5 ISOamsb
'sect'
:
'
\
247
'
,
# section sign, U+00A7 ISOnum
'shy'
:
'
\
255
'
,
# soft hyphen = discretionary hyphen, U+00AD ISOnum
'sigma'
:
'σ'
,
# greek small letter sigma, U+03C3 ISOgrk3
'sigmaf'
:
'ς'
,
# greek small letter final sigma, U+03C2 ISOgrk3
'sim'
:
'∼'
,
# tilde operator = varies with = similar to, U+223C ISOtech
'spades'
:
'♠'
,
# black spade suit, U+2660 ISOpub
'sub'
:
'⊂'
,
# subset of, U+2282 ISOtech
'sube'
:
'⊆'
,
# subset of or equal to, U+2286 ISOtech
'sum'
:
'∑'
,
# n-ary sumation, U+2211 ISOamsb
'sup'
:
'⊃'
,
# superset of, U+2283 ISOtech
'sup1'
:
'
\
271
'
,
# superscript one = superscript digit one, U+00B9 ISOnum
'sup2'
:
'
\
262
'
,
# superscript two = superscript digit two = squared, U+00B2 ISOnum
'sup3'
:
'
\
263
'
,
# superscript three = superscript digit three = cubed, U+00B3 ISOnum
'supe'
:
'⊇'
,
# superset of or equal to, U+2287 ISOtech
'szlig'
:
'
\
337
'
,
# latin small letter sharp s = ess-zed, U+00DF ISOlat1
'tau'
:
'τ'
,
# greek small letter tau, U+03C4 ISOgrk3
'there4'
:
'∴'
,
# therefore, U+2234 ISOtech
'theta'
:
'θ'
,
# greek small letter theta, U+03B8 ISOgrk3
'thetasym'
:
'ϑ'
,
# greek small letter theta symbol, U+03D1 NEW
'thinsp'
:
' '
,
# thin space, U+2009 ISOpub
'thorn'
:
'
\
376
'
,
# latin small letter thorn with, U+00FE ISOlat1
'tilde'
:
'˜'
,
# small tilde, U+02DC ISOdia
'times'
:
'
\
327
'
,
# multiplication sign, U+00D7 ISOnum
'trade'
:
'™'
,
# trade mark sign, U+2122 ISOnum
'uArr'
:
'⇑'
,
# upwards double arrow, U+21D1 ISOamsa
'uacute'
:
'
\
372
'
,
# latin small letter u with acute, U+00FA ISOlat1
'uarr'
:
'↑'
,
# upwards arrow, U+2191 ISOnum
'ucirc'
:
'
\
373
'
,
# latin small letter u with circumflex, U+00FB ISOlat1
'ugrave'
:
'
\
371
'
,
# latin small letter u with grave, U+00F9 ISOlat1
'uml'
:
'
\
250
'
,
# diaeresis = spacing diaeresis, U+00A8 ISOdia
'upsih'
:
'ϒ'
,
# greek upsilon with hook symbol, U+03D2 NEW
'upsilon'
:
'υ'
,
# greek small letter upsilon, U+03C5 ISOgrk3
'uuml'
:
'
\
374
'
,
# latin small letter u with diaeresis, U+00FC ISOlat1
'weierp'
:
'℘'
,
# script capital P = power set = Weierstrass p, U+2118 ISOamso
'xi'
:
'ξ'
,
# greek small letter xi, U+03BE ISOgrk3
'yacute'
:
'
\
375
'
,
# latin small letter y with acute, U+00FD ISOlat1
'yen'
:
'
\
245
'
,
# yen sign = yuan sign, U+00A5 ISOnum
'yuml'
:
'
\
377
'
,
# latin small letter y with diaeresis, U+00FF ISOlat1
'zeta'
:
'ζ'
,
# greek small letter zeta, U+03B6 ISOgrk3
'zwj'
:
'‍'
,
# zero width joiner, U+200D NEW RFC 2070
'zwnj'
:
'‌'
,
# zero width non-joiner, U+200C NEW RFC 2070
'AElig'
:
'
\
306
'
,
# latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1
'Aacute'
:
'
\
301
'
,
# latin capital letter A with acute, U+00C1 ISOlat1
'Acirc'
:
'
\
302
'
,
# latin capital letter A with circumflex, U+00C2 ISOlat1
'Agrave'
:
'
\
300
'
,
# latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1
'Alpha'
:
'Α'
,
# greek capital letter alpha, U+0391
'Aring'
:
'
\
305
'
,
# latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1
'Atilde'
:
'
\
303
'
,
# latin capital letter A with tilde, U+00C3 ISOlat1
'Auml'
:
'
\
304
'
,
# latin capital letter A with diaeresis, U+00C4 ISOlat1
'Beta'
:
'Β'
,
# greek capital letter beta, U+0392
'Ccedil'
:
'
\
307
'
,
# latin capital letter C with cedilla, U+00C7 ISOlat1
'Chi'
:
'Χ'
,
# greek capital letter chi, U+03A7
'Dagger'
:
'‡'
,
# double dagger, U+2021 ISOpub
'Delta'
:
'Δ'
,
# greek capital letter delta, U+0394 ISOgrk3
'ETH'
:
'
\
320
'
,
# latin capital letter ETH, U+00D0 ISOlat1
'Eacute'
:
'
\
311
'
,
# latin capital letter E with acute, U+00C9 ISOlat1
'Ecirc'
:
'
\
312
'
,
# latin capital letter E with circumflex, U+00CA ISOlat1
'Egrave'
:
'
\
310
'
,
# latin capital letter E with grave, U+00C8 ISOlat1
'Epsilon'
:
'Ε'
,
# greek capital letter epsilon, U+0395
'Eta'
:
'Η'
,
# greek capital letter eta, U+0397
'Euml'
:
'
\
313
'
,
# latin capital letter E with diaeresis, U+00CB ISOlat1
'Gamma'
:
'Γ'
,
# greek capital letter gamma, U+0393 ISOgrk3
'Iacute'
:
'
\
315
'
,
# latin capital letter I with acute, U+00CD ISOlat1
'Icirc'
:
'
\
316
'
,
# latin capital letter I with circumflex, U+00CE ISOlat1
'Igrave'
:
'
\
314
'
,
# latin capital letter I with grave, U+00CC ISOlat1
'Iota'
:
'Ι'
,
# greek capital letter iota, U+0399
'Iuml'
:
'
\
317
'
,
# latin capital letter I with diaeresis, U+00CF ISOlat1
'Kappa'
:
'Κ'
,
# greek capital letter kappa, U+039A
'Lambda'
:
'Λ'
,
# greek capital letter lambda, U+039B ISOgrk3
'Mu'
:
'Μ'
,
# greek capital letter mu, U+039C
'Ntilde'
:
'
\
321
'
,
# latin capital letter N with tilde, U+00D1 ISOlat1
'Nu'
:
'Ν'
,
# greek capital letter nu, U+039D
'OElig'
:
'Œ'
,
# latin capital ligature OE, U+0152 ISOlat2
'Oacute'
:
'
\
323
'
,
# latin capital letter O with acute, U+00D3 ISOlat1
'Ocirc'
:
'
\
324
'
,
# latin capital letter O with circumflex, U+00D4 ISOlat1
'Ograve'
:
'
\
322
'
,
# latin capital letter O with grave, U+00D2 ISOlat1
'Omega'
:
'Ω'
,
# greek capital letter omega, U+03A9 ISOgrk3
'Omicron'
:
'Ο'
,
# greek capital letter omicron, U+039F
'Oslash'
:
'
\
330
'
,
# latin capital letter O with stroke = latin capital letter O slash, U+00D8 ISOlat1
'Otilde'
:
'
\
325
'
,
# latin capital letter O with tilde, U+00D5 ISOlat1
'Ouml'
:
'
\
326
'
,
# latin capital letter O with diaeresis, U+00D6 ISOlat1
'Phi'
:
'Φ'
,
# greek capital letter phi, U+03A6 ISOgrk3
'Pi'
:
'Π'
,
# greek capital letter pi, U+03A0 ISOgrk3
'Prime'
:
'″'
,
# double prime = seconds = inches, U+2033 ISOtech
'Psi'
:
'Ψ'
,
# greek capital letter psi, U+03A8 ISOgrk3
'Rho'
:
'Ρ'
,
# greek capital letter rho, U+03A1
'Scaron'
:
'Š'
,
# latin capital letter S with caron, U+0160 ISOlat2
'Sigma'
:
'Σ'
,
# greek capital letter sigma, U+03A3 ISOgrk3
'THORN'
:
'
\
336
'
,
# latin capital letter THORN, U+00DE ISOlat1
'Tau'
:
'Τ'
,
# greek capital letter tau, U+03A4
'Theta'
:
'Θ'
,
# greek capital letter theta, U+0398 ISOgrk3
'Uacute'
:
'
\
332
'
,
# latin capital letter U with acute, U+00DA ISOlat1
'Ucirc'
:
'
\
333
'
,
# latin capital letter U with circumflex, U+00DB ISOlat1
'Ugrave'
:
'
\
331
'
,
# latin capital letter U with grave, U+00D9 ISOlat1
'Upsilon'
:
'Υ'
,
# greek capital letter upsilon, U+03A5 ISOgrk3
'Uuml'
:
'
\
334
'
,
# latin capital letter U with diaeresis, U+00DC ISOlat1
'Xi'
:
'Ξ'
,
# greek capital letter xi, U+039E ISOgrk3
'Yacute'
:
'
\
335
'
,
# latin capital letter Y with acute, U+00DD ISOlat1
'Yuml'
:
'Ÿ'
,
# latin capital letter Y with diaeresis, U+0178 ISOlat2
'Zeta'
:
'Ζ'
,
# greek capital letter zeta, U+0396
'aacute'
:
'
\
341
'
,
# latin small letter a with acute, U+00E1 ISOlat1
'acirc'
:
'
\
342
'
,
# latin small letter a with circumflex, U+00E2 ISOlat1
'acute'
:
'
\
264
'
,
# acute accent = spacing acute, U+00B4 ISOdia
'aelig'
:
'
\
346
'
,
# latin small letter ae = latin small ligature ae, U+00E6 ISOlat1
'agrave'
:
'
\
340
'
,
# latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1
'alefsym'
:
'ℵ'
,
# alef symbol = first transfinite cardinal, U+2135 NEW
'alpha'
:
'α'
,
# greek small letter alpha, U+03B1 ISOgrk3
'amp'
:
'
\
46
'
,
# ampersand, U+0026 ISOnum
'and'
:
'∧'
,
# logical and = wedge, U+2227 ISOtech
'ang'
:
'∠'
,
# angle, U+2220 ISOamso
'aring'
:
'
\
345
'
,
# latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1
'asymp'
:
'≈'
,
# almost equal to = asymptotic to, U+2248 ISOamsr
'atilde'
:
'
\
343
'
,
# latin small letter a with tilde, U+00E3 ISOlat1
'auml'
:
'
\
344
'
,
# latin small letter a with diaeresis, U+00E4 ISOlat1
'bdquo'
:
'„'
,
# double low-9 quotation mark, U+201E NEW
'beta'
:
'β'
,
# greek small letter beta, U+03B2 ISOgrk3
'brvbar'
:
'
\
246
'
,
# broken bar = broken vertical bar, U+00A6 ISOnum
'bull'
:
'•'
,
# bullet = black small circle, U+2022 ISOpub
'cap'
:
'∩'
,
# intersection = cap, U+2229 ISOtech
'ccedil'
:
'
\
347
'
,
# latin small letter c with cedilla, U+00E7 ISOlat1
'cedil'
:
'
\
270
'
,
# cedilla = spacing cedilla, U+00B8 ISOdia
'cent'
:
'
\
242
'
,
# cent sign, U+00A2 ISOnum
'chi'
:
'χ'
,
# greek small letter chi, U+03C7 ISOgrk3
'circ'
:
'ˆ'
,
# modifier letter circumflex accent, U+02C6 ISOpub
'clubs'
:
'♣'
,
# black club suit = shamrock, U+2663 ISOpub
'cong'
:
'≅'
,
# approximately equal to, U+2245 ISOtech
'copy'
:
'
\
251
'
,
# copyright sign, U+00A9 ISOnum
'crarr'
:
'↵'
,
# downwards arrow with corner leftwards = carriage return, U+21B5 NEW
'cup'
:
'∪'
,
# union = cup, U+222A ISOtech
'curren'
:
'
\
244
'
,
# currency sign, U+00A4 ISOnum
'dArr'
:
'⇓'
,
# downwards double arrow, U+21D3 ISOamsa
'dagger'
:
'†'
,
# dagger, U+2020 ISOpub
'darr'
:
'↓'
,
# downwards arrow, U+2193 ISOnum
'deg'
:
'
\
260
'
,
# degree sign, U+00B0 ISOnum
'delta'
:
'δ'
,
# greek small letter delta, U+03B4 ISOgrk3
'diams'
:
'♦'
,
# black diamond suit, U+2666 ISOpub
'divide'
:
'
\
367
'
,
# division sign, U+00F7 ISOnum
'eacute'
:
'
\
351
'
,
# latin small letter e with acute, U+00E9 ISOlat1
'ecirc'
:
'
\
352
'
,
# latin small letter e with circumflex, U+00EA ISOlat1
'egrave'
:
'
\
350
'
,
# latin small letter e with grave, U+00E8 ISOlat1
'empty'
:
'∅'
,
# empty set = null set = diameter, U+2205 ISOamso
'emsp'
:
' '
,
# em space, U+2003 ISOpub
'ensp'
:
' '
,
# en space, U+2002 ISOpub
'epsilon'
:
'ε'
,
# greek small letter epsilon, U+03B5 ISOgrk3
'equiv'
:
'≡'
,
# identical to, U+2261 ISOtech
'eta'
:
'η'
,
# greek small letter eta, U+03B7 ISOgrk3
'eth'
:
'
\
360
'
,
# latin small letter eth, U+00F0 ISOlat1
'euml'
:
'
\
353
'
,
# latin small letter e with diaeresis, U+00EB ISOlat1
'euro'
:
'€'
,
# euro sign, U+20AC NEW
'exist'
:
'∃'
,
# there exists, U+2203 ISOtech
'fnof'
:
'ƒ'
,
# latin small f with hook = function = florin, U+0192 ISOtech
'forall'
:
'∀'
,
# for all, U+2200 ISOtech
'frac12'
:
'
\
275
'
,
# vulgar fraction one half = fraction one half, U+00BD ISOnum
'frac14'
:
'
\
274
'
,
# vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum
'frac34'
:
'
\
276
'
,
# vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum
'frasl'
:
'⁄'
,
# fraction slash, U+2044 NEW
'gamma'
:
'γ'
,
# greek small letter gamma, U+03B3 ISOgrk3
'ge'
:
'≥'
,
# greater-than or equal to, U+2265 ISOtech
'gt'
:
'
\
76
'
,
# greater-than sign, U+003E ISOnum
'hArr'
:
'⇔'
,
# left right double arrow, U+21D4 ISOamsa
'harr'
:
'↔'
,
# left right arrow, U+2194 ISOamsa
'hearts'
:
'♥'
,
# black heart suit = valentine, U+2665 ISOpub
'hellip'
:
'…'
,
# horizontal ellipsis = three dot leader, U+2026 ISOpub
'iacute'
:
'
\
355
'
,
# latin small letter i with acute, U+00ED ISOlat1
'icirc'
:
'
\
356
'
,
# latin small letter i with circumflex, U+00EE ISOlat1
'iexcl'
:
'
\
241
'
,
# inverted exclamation mark, U+00A1 ISOnum
'igrave'
:
'
\
354
'
,
# latin small letter i with grave, U+00EC ISOlat1
'image'
:
'ℑ'
,
# blackletter capital I = imaginary part, U+2111 ISOamso
'infin'
:
'∞'
,
# infinity, U+221E ISOtech
'int'
:
'∫'
,
# integral, U+222B ISOtech
'iota'
:
'ι'
,
# greek small letter iota, U+03B9 ISOgrk3
'iquest'
:
'
\
277
'
,
# inverted question mark = turned question mark, U+00BF ISOnum
'isin'
:
'∈'
,
# element of, U+2208 ISOtech
'iuml'
:
'
\
357
'
,
# latin small letter i with diaeresis, U+00EF ISOlat1
'kappa'
:
'κ'
,
# greek small letter kappa, U+03BA ISOgrk3
'lArr'
:
'⇐'
,
# leftwards double arrow, U+21D0 ISOtech
'lambda'
:
'λ'
,
# greek small letter lambda, U+03BB ISOgrk3
'lang'
:
'〈'
,
# left-pointing angle bracket = bra, U+2329 ISOtech
'laquo'
:
'
\
253
'
,
# left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum
'larr'
:
'←'
,
# leftwards arrow, U+2190 ISOnum
'lceil'
:
'⌈'
,
# left ceiling = apl upstile, U+2308 ISOamsc
'ldquo'
:
'“'
,
# left double quotation mark, U+201C ISOnum
'le'
:
'≤'
,
# less-than or equal to, U+2264 ISOtech
'lfloor'
:
'⌊'
,
# left floor = apl downstile, U+230A ISOamsc
'lowast'
:
'∗'
,
# asterisk operator, U+2217 ISOtech
'loz'
:
'◊'
,
# lozenge, U+25CA ISOpub
'lrm'
:
'‎'
,
# left-to-right mark, U+200E NEW RFC 2070
'lsaquo'
:
'‹'
,
# single left-pointing angle quotation mark, U+2039 ISO proposed
'lsquo'
:
'‘'
,
# left single quotation mark, U+2018 ISOnum
'lt'
:
'
\
74
'
,
# less-than sign, U+003C ISOnum
'macr'
:
'
\
257
'
,
# macron = spacing macron = overline = APL overbar, U+00AF ISOdia
'mdash'
:
'—'
,
# em dash, U+2014 ISOpub
'micro'
:
'
\
265
'
,
# micro sign, U+00B5 ISOnum
'middot'
:
'
\
267
'
,
# middle dot = Georgian comma = Greek middle dot, U+00B7 ISOnum
'minus'
:
'−'
,
# minus sign, U+2212 ISOtech
'mu'
:
'μ'
,
# greek small letter mu, U+03BC ISOgrk3
'nabla'
:
'∇'
,
# nabla = backward difference, U+2207 ISOtech
'nbsp'
:
'
\
240
'
,
# no-break space = non-breaking space, U+00A0 ISOnum
'ndash'
:
'–'
,
# en dash, U+2013 ISOpub
'ne'
:
'≠'
,
# not equal to, U+2260 ISOtech
'ni'
:
'∋'
,
# contains as member, U+220B ISOtech
'not'
:
'
\
254
'
,
# not sign, U+00AC ISOnum
'notin'
:
'∉'
,
# not an element of, U+2209 ISOtech
'nsub'
:
'⊄'
,
# not a subset of, U+2284 ISOamsn
'ntilde'
:
'
\
361
'
,
# latin small letter n with tilde, U+00F1 ISOlat1
'nu'
:
'ν'
,
# greek small letter nu, U+03BD ISOgrk3
'oacute'
:
'
\
363
'
,
# latin small letter o with acute, U+00F3 ISOlat1
'ocirc'
:
'
\
364
'
,
# latin small letter o with circumflex, U+00F4 ISOlat1
'oelig'
:
'œ'
,
# latin small ligature oe, U+0153 ISOlat2
'ograve'
:
'
\
362
'
,
# latin small letter o with grave, U+00F2 ISOlat1
'oline'
:
'‾'
,
# overline = spacing overscore, U+203E NEW
'omega'
:
'ω'
,
# greek small letter omega, U+03C9 ISOgrk3
'omicron'
:
'ο'
,
# greek small letter omicron, U+03BF NEW
'oplus'
:
'⊕'
,
# circled plus = direct sum, U+2295 ISOamsb
'or'
:
'∨'
,
# logical or = vee, U+2228 ISOtech
'ordf'
:
'
\
252
'
,
# feminine ordinal indicator, U+00AA ISOnum
'ordm'
:
'
\
272
'
,
# masculine ordinal indicator, U+00BA ISOnum
'oslash'
:
'
\
370
'
,
# latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1
'otilde'
:
'
\
365
'
,
# latin small letter o with tilde, U+00F5 ISOlat1
'otimes'
:
'⊗'
,
# circled times = vector product, U+2297 ISOamsb
'ouml'
:
'
\
366
'
,
# latin small letter o with diaeresis, U+00F6 ISOlat1
'para'
:
'
\
266
'
,
# pilcrow sign = paragraph sign, U+00B6 ISOnum
'part'
:
'∂'
,
# partial differential, U+2202 ISOtech
'permil'
:
'‰'
,
# per mille sign, U+2030 ISOtech
'perp'
:
'⊥'
,
# up tack = orthogonal to = perpendicular, U+22A5 ISOtech
'phi'
:
'φ'
,
# greek small letter phi, U+03C6 ISOgrk3
'pi'
:
'π'
,
# greek small letter pi, U+03C0 ISOgrk3
'piv'
:
'ϖ'
,
# greek pi symbol, U+03D6 ISOgrk3
'plusmn'
:
'
\
261
'
,
# plus-minus sign = plus-or-minus sign, U+00B1 ISOnum
'pound'
:
'
\
243
'
,
# pound sign, U+00A3 ISOnum
'prime'
:
'′'
,
# prime = minutes = feet, U+2032 ISOtech
'prod'
:
'∏'
,
# n-ary product = product sign, U+220F ISOamsb
'prop'
:
'∝'
,
# proportional to, U+221D ISOtech
'psi'
:
'ψ'
,
# greek small letter psi, U+03C8 ISOgrk3
'quot'
:
'
\
42
'
,
# quotation mark = APL quote, U+0022 ISOnum
'rArr'
:
'⇒'
,
# rightwards double arrow, U+21D2 ISOtech
'radic'
:
'√'
,
# square root = radical sign, U+221A ISOtech
'rang'
:
'〉'
,
# right-pointing angle bracket = ket, U+232A ISOtech
'raquo'
:
'
\
273
'
,
# right-pointing double angle quotation mark = right pointing guillemet, U+00BB ISOnum
'rarr'
:
'→'
,
# rightwards arrow, U+2192 ISOnum
'rceil'
:
'⌉'
,
# right ceiling, U+2309 ISOamsc
'rdquo'
:
'”'
,
# right double quotation mark, U+201D ISOnum
'real'
:
'ℜ'
,
# blackletter capital R = real part symbol, U+211C ISOamso
'reg'
:
'
\
256
'
,
# registered sign = registered trade mark sign, U+00AE ISOnum
'rfloor'
:
'⌋'
,
# right floor, U+230B ISOamsc
'rho'
:
'ρ'
,
# greek small letter rho, U+03C1 ISOgrk3
'rlm'
:
'‏'
,
# right-to-left mark, U+200F NEW RFC 2070
'rsaquo'
:
'›'
,
# single right-pointing angle quotation mark, U+203A ISO proposed
'rsquo'
:
'’'
,
# right single quotation mark, U+2019 ISOnum
'sbquo'
:
'‚'
,
# single low-9 quotation mark, U+201A NEW
'scaron'
:
'š'
,
# latin small letter s with caron, U+0161 ISOlat2
'sdot'
:
'⋅'
,
# dot operator, U+22C5 ISOamsb
'sect'
:
'
\
247
'
,
# section sign, U+00A7 ISOnum
'shy'
:
'
\
255
'
,
# soft hyphen = discretionary hyphen, U+00AD ISOnum
'sigma'
:
'σ'
,
# greek small letter sigma, U+03C3 ISOgrk3
'sigmaf'
:
'ς'
,
# greek small letter final sigma, U+03C2 ISOgrk3
'sim'
:
'∼'
,
# tilde operator = varies with = similar to, U+223C ISOtech
'spades'
:
'♠'
,
# black spade suit, U+2660 ISOpub
'sub'
:
'⊂'
,
# subset of, U+2282 ISOtech
'sube'
:
'⊆'
,
# subset of or equal to, U+2286 ISOtech
'sum'
:
'∑'
,
# n-ary sumation, U+2211 ISOamsb
'sup'
:
'⊃'
,
# superset of, U+2283 ISOtech
'sup1'
:
'
\
271
'
,
# superscript one = superscript digit one, U+00B9 ISOnum
'sup2'
:
'
\
262
'
,
# superscript two = superscript digit two = squared, U+00B2 ISOnum
'sup3'
:
'
\
263
'
,
# superscript three = superscript digit three = cubed, U+00B3 ISOnum
'supe'
:
'⊇'
,
# superset of or equal to, U+2287 ISOtech
'szlig'
:
'
\
337
'
,
# latin small letter sharp s = ess-zed, U+00DF ISOlat1
'tau'
:
'τ'
,
# greek small letter tau, U+03C4 ISOgrk3
'there4'
:
'∴'
,
# therefore, U+2234 ISOtech
'theta'
:
'θ'
,
# greek small letter theta, U+03B8 ISOgrk3
'thetasym'
:
'ϑ'
,
# greek small letter theta symbol, U+03D1 NEW
'thinsp'
:
' '
,
# thin space, U+2009 ISOpub
'thorn'
:
'
\
376
'
,
# latin small letter thorn with, U+00FE ISOlat1
'tilde'
:
'˜'
,
# small tilde, U+02DC ISOdia
'times'
:
'
\
327
'
,
# multiplication sign, U+00D7 ISOnum
'trade'
:
'™'
,
# trade mark sign, U+2122 ISOnum
'uArr'
:
'⇑'
,
# upwards double arrow, U+21D1 ISOamsa
'uacute'
:
'
\
372
'
,
# latin small letter u with acute, U+00FA ISOlat1
'uarr'
:
'↑'
,
# upwards arrow, U+2191 ISOnum
'ucirc'
:
'
\
373
'
,
# latin small letter u with circumflex, U+00FB ISOlat1
'ugrave'
:
'
\
371
'
,
# latin small letter u with grave, U+00F9 ISOlat1
'uml'
:
'
\
250
'
,
# diaeresis = spacing diaeresis, U+00A8 ISOdia
'upsih'
:
'ϒ'
,
# greek upsilon with hook symbol, U+03D2 NEW
'upsilon'
:
'υ'
,
# greek small letter upsilon, U+03C5 ISOgrk3
'uuml'
:
'
\
374
'
,
# latin small letter u with diaeresis, U+00FC ISOlat1
'weierp'
:
'℘'
,
# script capital P = power set = Weierstrass p, U+2118 ISOamso
'xi'
:
'ξ'
,
# greek small letter xi, U+03BE ISOgrk3
'yacute'
:
'
\
375
'
,
# latin small letter y with acute, U+00FD ISOlat1
'yen'
:
'
\
245
'
,
# yen sign = yuan sign, U+00A5 ISOnum
'yuml'
:
'
\
377
'
,
# latin small letter y with diaeresis, U+00FF ISOlat1
'zeta'
:
'ζ'
,
# greek small letter zeta, U+03B6 ISOgrk3
'zwj'
:
'‍'
,
# zero width joiner, U+200D NEW RFC 2070
'zwnj'
:
'‌'
,
# zero width non-joiner, U+200C NEW RFC 2070
}
Lib/htmllib.py
View file @
463a4d72
...
...
@@ -411,7 +411,7 @@ def test(args = None):
if
f
is
not
sys
.
stdin
:
f
.
close
()
if
silent
:
f
=
formatter
.
NullFormatter
()
else
:
...
...
Lib/httplib.py
View file @
463a4d72
...
...
@@ -93,14 +93,14 @@ class HTTPResponse:
self
.
msg
=
None
# from the Status-Line of the response
self
.
version
=
_UNKNOWN
# HTTP-Version
self
.
status
=
_UNKNOWN
# Status-Code
self
.
reason
=
_UNKNOWN
# Reason-Phrase
self
.
version
=
_UNKNOWN
# HTTP-Version
self
.
status
=
_UNKNOWN
# Status-Code
self
.
reason
=
_UNKNOWN
# Reason-Phrase
self
.
chunked
=
_UNKNOWN
# is "chunked" being used?
self
.
chunk_left
=
_UNKNOWN
# bytes left to read in current chunk
self
.
length
=
_UNKNOWN
# number of bytes left in response
self
.
will_close
=
_UNKNOWN
# conn will close at end of response
self
.
chunked
=
_UNKNOWN
# is "chunked" being used?
self
.
chunk_left
=
_UNKNOWN
# bytes left to read in current chunk
self
.
length
=
_UNKNOWN
# number of bytes left in response
self
.
will_close
=
_UNKNOWN
# conn will close at end of response
def
begin
(
self
):
if
self
.
msg
is
not
None
:
...
...
@@ -130,7 +130,7 @@ class HTTPResponse:
if
version
==
'HTTP/1.0'
:
self
.
version
=
10
elif
version
.
startswith
(
'HTTP/1.'
):
self
.
version
=
11
# use HTTP/1.1 code for HTTP/1.x where x>=1
self
.
version
=
11
# use HTTP/1.1 code for HTTP/1.x where x>=1
elif
version
==
'HTTP/0.9'
:
self
.
version
=
9
else
:
...
...
@@ -186,9 +186,9 @@ class HTTPResponse:
self
.
length
=
None
# does the body have a fixed length? (of zero)
if
(
status
==
204
or
# No Content
status
==
304
or
# Not Modified
100
<=
status
<
200
):
# 1xx codes
if
(
status
==
204
or
# No Content
status
==
304
or
# Not Modified
100
<=
status
<
200
):
# 1xx codes
self
.
length
=
0
# if the connection remains open, and we aren't using chunked, and
...
...
@@ -225,7 +225,7 @@ class HTTPResponse:
line
=
self
.
fp
.
readline
()
i
=
line
.
find
(
';'
)
if
i
>=
0
:
line
=
line
[:
i
]
# strip chunk-extensions
line
=
line
[:
i
]
# strip chunk-extensions
chunk_left
=
int
(
line
,
16
)
if
chunk_left
==
0
:
break
...
...
@@ -237,7 +237,7 @@ class HTTPResponse:
return
value
elif
amt
==
chunk_left
:
value
=
value
+
self
.
_safe_read
(
amt
)
self
.
_safe_read
(
2
)
# toss the CRLF at the end of the chunk
self
.
_safe_read
(
2
)
# toss the CRLF at the end of the chunk
self
.
chunk_left
=
None
return
value
else
:
...
...
@@ -245,7 +245,7 @@ class HTTPResponse:
amt
=
amt
-
chunk_left
# we read the whole chunk, get another
self
.
_safe_read
(
2
)
# toss the CRLF at the end of the chunk
self
.
_safe_read
(
2
)
# toss the CRLF at the end of the chunk
chunk_left
=
None
# read and discard trailer up to the CRLF terminator
...
...
@@ -266,7 +266,7 @@ class HTTPResponse:
s
=
self
.
fp
.
read
()
else
:
s
=
self
.
_safe_read
(
self
.
length
)
self
.
close
()
# we read everything
self
.
close
()
# we read everything
return
s
if
self
.
length
is
not
None
:
...
...
@@ -355,7 +355,7 @@ class HTTPConnection:
def
close
(
self
):
"""Close the connection to the HTTP server."""
if
self
.
sock
:
self
.
sock
.
close
()
# close it manually... there may be other refs
self
.
sock
.
close
()
# close it manually... there may be other refs
self
.
sock
=
None
if
self
.
__response
:
self
.
__response
.
close
()
...
...
@@ -380,7 +380,7 @@ class HTTPConnection:
try
:
self
.
sock
.
send
(
str
)
except
socket
.
error
,
v
:
if
v
[
0
]
==
32
:
# Broken pipe
if
v
[
0
]
==
32
:
# Broken pipe
self
.
close
()
raise
...
...
Lib/ihooks.py
View file @
463a4d72
...
...
@@ -109,7 +109,7 @@ class BasicModuleLoader(_Verbose):
"""
def
find_module
(
self
,
name
,
path
=
None
):
if
path
is
None
:
if
path
is
None
:
path
=
[
None
]
+
self
.
default_path
()
for
dir
in
path
:
stuff
=
self
.
find_module_in_dir
(
name
,
dir
)
...
...
@@ -390,7 +390,7 @@ class BasicModuleImporter(_Verbose):
class
ModuleImporter
(
BasicModuleImporter
):
"""A module importer that supports packages."""
def
import_module
(
self
,
name
,
globals
=
None
,
locals
=
None
,
fromlist
=
None
):
parent
=
self
.
determine_parent
(
globals
)
q
,
tail
=
self
.
find_head_package
(
parent
,
name
)
...
...
Lib/imaplib.py
View file @
463a4d72
"""IMAP4 client.
Based on RFC 2060.
Public class:
IMAP4
Public variable:
Debug
Public functions:
Internaldate2tuple
Int2AP
ParseFlags
Time2Internaldate
Public class:
IMAP4
Public variable:
Debug
Public functions:
Internaldate2tuple
Int2AP
ParseFlags
Time2Internaldate
"""
# Author: Piers Lauder <piers@cs.su.oz.au> December 1997.
#
#
# Authentication code contributed by Donn Cave <donn@u.washington.edu> June 1998.
__version__
=
"2.39"
import
binascii
,
re
,
socket
,
string
,
time
,
random
,
sys
#
Globals
#
Globals
CRLF
=
'
\
r
\
n
'
Debug
=
0
IMAP4_PORT
=
143
AllowedVersions
=
(
'IMAP4REV1'
,
'IMAP4'
)
# Most recent first
AllowedVersions
=
(
'IMAP4REV1'
,
'IMAP4'
)
# Most recent first
#
Commands
#
Commands
Commands
=
{
# name
valid states
'APPEND'
:
(
'AUTH'
,
'SELECTED'
),
'AUTHENTICATE'
:
(
'NONAUTH'
,),
'CAPABILITY'
:
(
'NONAUTH'
,
'AUTH'
,
'SELECTED'
,
'LOGOUT'
),
'CHECK'
:
(
'SELECTED'
,),
'CLOSE'
:
(
'SELECTED'
,),
'COPY'
:
(
'SELECTED'
,),
'CREATE'
:
(
'AUTH'
,
'SELECTED'
),
'DELETE'
:
(
'AUTH'
,
'SELECTED'
),
'EXAMINE'
:
(
'AUTH'
,
'SELECTED'
),
'EXPUNGE'
:
(
'SELECTED'
,),
'FETCH'
:
(
'SELECTED'
,),
'LIST'
:
(
'AUTH'
,
'SELECTED'
),
'LOGIN'
:
(
'NONAUTH'
,),
'LOGOUT'
:
(
'NONAUTH'
,
'AUTH'
,
'SELECTED'
,
'LOGOUT'
),
'LSUB'
:
(
'AUTH'
,
'SELECTED'
),
'NOOP'
:
(
'NONAUTH'
,
'AUTH'
,
'SELECTED'
,
'LOGOUT'
),
'PARTIAL'
:
(
'SELECTED'
,),
'RENAME'
:
(
'AUTH'
,
'SELECTED'
),
'SEARCH'
:
(
'SELECTED'
,),
'SELECT'
:
(
'AUTH'
,
'SELECTED'
),
'STATUS'
:
(
'AUTH'
,
'SELECTED'
),
'STORE'
:
(
'SELECTED'
,),
'SUBSCRIBE'
:
(
'AUTH'
,
'SELECTED'
),
'UID'
:
(
'SELECTED'
,),
'UNSUBSCRIBE'
:
(
'AUTH'
,
'SELECTED'
),
}
#
Patterns to match server responses
# name
valid states
'APPEND'
:
(
'AUTH'
,
'SELECTED'
),
'AUTHENTICATE'
:
(
'NONAUTH'
,),
'CAPABILITY'
:
(
'NONAUTH'
,
'AUTH'
,
'SELECTED'
,
'LOGOUT'
),
'CHECK'
:
(
'SELECTED'
,),
'CLOSE'
:
(
'SELECTED'
,),
'COPY'
:
(
'SELECTED'
,),
'CREATE'
:
(
'AUTH'
,
'SELECTED'
),
'DELETE'
:
(
'AUTH'
,
'SELECTED'
),
'EXAMINE'
:
(
'AUTH'
,
'SELECTED'
),
'EXPUNGE'
:
(
'SELECTED'
,),
'FETCH'
:
(
'SELECTED'
,),
'LIST'
:
(
'AUTH'
,
'SELECTED'
),
'LOGIN'
:
(
'NONAUTH'
,),
'LOGOUT'
:
(
'NONAUTH'
,
'AUTH'
,
'SELECTED'
,
'LOGOUT'
),
'LSUB'
:
(
'AUTH'
,
'SELECTED'
),
'NOOP'
:
(
'NONAUTH'
,
'AUTH'
,
'SELECTED'
,
'LOGOUT'
),
'PARTIAL'
:
(
'SELECTED'
,),
'RENAME'
:
(
'AUTH'
,
'SELECTED'
),
'SEARCH'
:
(
'SELECTED'
,),
'SELECT'
:
(
'AUTH'
,
'SELECTED'
),
'STATUS'
:
(
'AUTH'
,
'SELECTED'
),
'STORE'
:
(
'SELECTED'
,),
'SUBSCRIBE'
:
(
'AUTH'
,
'SELECTED'
),
'UID'
:
(
'SELECTED'
,),
'UNSUBSCRIBE'
:
(
'AUTH'
,
'SELECTED'
),
}
#
Patterns to match server responses
Continuation
=
re
.
compile
(
r'\
+( (?P<d
ata>.*))?'
)
Flags
=
re
.
compile
(
r'.*FLAGS \
((?P<
flags>[^\
)]*)
\)'
)
InternalDate
=
re
.
compile
(
r'.*INTERNALDATE "'
r'(?P<day>[ 123][0-9])-(?P<mon>[A-Z][a-z][a-z])-(?P<year>[0-9][0-9][0-9][0-9])'
r' (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9])'
r' (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])'
r'"'
)
r'(?P<day>[ 123][0-9])-(?P<mon>[A-Z][a-z][a-z])-(?P<year>[0-9][0-9][0-9][0-9])'
r' (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9])'
r' (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])'
r'"'
)
Literal
=
re
.
compile
(
r'.*{(?P<size>\
d+)}$
')
Response_code = re.compile(r'
\
[(
?
P
<
type
>
[
A
-
Z
-
]
+
)(
(
?
P
<
data
>
[
^
\
]]
*
))
?
\
]
')
Untagged_response = re.compile(r'
\
*
(
?
P
<
type
>
[
A
-
Z
-
]
+
)(
(
?
P
<
data
>
.
*
))
?
')
...
...
@@ -75,1045 +74,1045 @@ Untagged_status = re.compile(r'\* (?P<data>\d+) (?P<type>[A-Z-]+)( (?P<data2>.*)
class IMAP4:
"""IMAP4 client class.
Instantiate with: IMAP4([host[, port]])
host - host'
s
name
(
default
:
localhost
);
port
-
port
number
(
default
:
standard
IMAP4
port
).
All
IMAP4rev1
commands
are
supported
by
methods
of
the
same
name
(
in
lower
-
case
).
All
arguments
to
commands
are
converted
to
strings
,
except
for
AUTHENTICATE
,
and
the
last
argument
to
APPEND
which
is
passed
as
an
IMAP4
literal
.
If
necessary
(
the
string
contains
any
non
-
printing
characters
or
white
-
space
and
isn
't enclosed with
either parentheses or double quotes) each string is quoted.
However, the '
password
' argument to the LOGIN command is always
quoted. If you want to avoid having an argument string quoted
(eg: the '
flags
' argument to STORE) then enclose the string in
parentheses (eg: "(
\
Dele
t
ed)").
"""IMAP4 client class.
Instantiate with: IMAP4([host[, port]])
host - host'
s
name
(
default
:
localhost
);
port
-
port
number
(
default
:
standard
IMAP4
port
).
All
IMAP4rev1
commands
are
supported
by
methods
of
the
same
name
(
in
lower
-
case
).
All
arguments
to
commands
are
converted
to
strings
,
except
for
AUTHENTICATE
,
and
the
last
argument
to
APPEND
which
is
passed
as
an
IMAP4
literal
.
If
necessary
(
the
string
contains
any
non
-
printing
characters
or
white
-
space
and
isn
't enclosed with
either parentheses or double quotes) each string is quoted.
However, the '
password
' argument to the LOGIN command is always
quoted. If you want to avoid having an argument string quoted
(eg: the '
flags
' argument to STORE) then enclose the string in
parentheses (eg: "(
\
Dele
t
ed)").
Each command returns a tuple: (type, [data, ...]) where '
type
'
is usually '
OK
' or '
NO
', and '
data
' is either the text from the
tagged response, or untagged results from command.
Each command returns a tuple: (type, [data, ...]) where '
type
'
is usually '
OK
' or '
NO
', and '
data
' is either the text from the
tagged response, or untagged results from command.
Errors raise the exception class <instance>.error("<reason>").
IMAP4 server errors raise <instance>.abort("<reason>"),
which is a sub-class of '
error
'. Mailbox status changes
from READ-WRITE to READ-ONLY raise the exception class
<instance>.readonly("<reason>"), which is a sub-class of '
abort
'.
Errors raise the exception class <instance>.error("<reason>").
IMAP4 server errors raise <instance>.abort("<reason>"),
which is a sub-class of '
error
'. Mailbox status changes
from READ-WRITE to READ-ONLY raise the exception class
<instance>.readonly("<reason>"), which is a sub-class of '
abort
'.
"error" exceptions imply a program error.
"abort" exceptions imply the connection should be reset, and
the command re-tried.
"readonly" exceptions imply the command should be re-tried.
"error" exceptions imply a program error.
"abort" exceptions imply the connection should be reset, and
the command re-tried.
"readonly" exceptions imply the command should be re-tried.
Note: to use this module, you must read the RFCs pertaining
to the IMAP4 protocol, as the semantics of the arguments to
each IMAP4 command are left to the invoker, not to mention
the results.
"""
Note: to use this module, you must read the RFCs pertaining
to the IMAP4 protocol, as the semantics of the arguments to
each IMAP4 command are left to the invoker, not to mention
the results.
"""
class error(Exception): pass
# Logical errors - debug required
class abort(error): pass
# Service errors - close and retry
class readonly(abort): pass
# Mailbox status changed to READ-ONLY
class error(Exception): pass
# Logical errors - debug required
class abort(error): pass
# Service errors - close and retry
class readonly(abort): pass
# Mailbox status changed to READ-ONLY
mustquote = re.compile(r"[^
\
w!#$%&
'
*+,.:;<=>?^`|~-]")
mustquote = re.compile(r"[^
\
w!#$%&
'
*+,.:;<=>?^`|~-]")
def __init__(self, host = '', port = IMAP4_PORT):
self.host = host
self.port = port
self.debug = Debug
self.state = '
LOGOUT
'
self.literal = None
# A literal argument to a command
self.tagged_commands = {}
# Tagged commands awaiting response
self.untagged_responses = {}
# {typ: [data, ...], ...}
self.continuation_response = ''
# Last continuation response
self.is_readonly = None
# READ-ONLY desired state
self.tagnum = 0
def __init__(self, host = '', port = IMAP4_PORT):
self.host = host
self.port = port
self.debug = Debug
self.state = '
LOGOUT
'
self.literal = None
# A literal argument to a command
self.tagged_commands = {}
# Tagged commands awaiting response
self.untagged_responses = {}
# {typ: [data, ...], ...}
self.continuation_response = ''
# Last continuation response
self.is_readonly = None
# READ-ONLY desired state
self.tagnum = 0
# Open socket to server.
# Open socket to server.
self.open(host, port)
self.open(host, port)
# Create unique tag for this session,
# and compile tagged response matcher.
# Create unique tag for this session,
# and compile tagged response matcher.
self.tagpre = Int2AP(random.randint(0, 31999))
self.tagre = re.compile(r'
(
?
P
<
tag
>
'
+ self.tagpre
+ r'
\
d
+
)
(
?
P
<
type
>
[
A
-
Z
]
+
)
(
?
P
<
data
>
.
*
)
')
self.tagpre = Int2AP(random.randint(0, 31999))
self.tagre = re.compile(r'
(
?
P
<
tag
>
'
+ self.tagpre
+ r'
\
d
+
)
(
?
P
<
type
>
[
A
-
Z
]
+
)
(
?
P
<
data
>
.
*
)
')
# Get server welcome message,
# request and store CAPABILITY response.
# Get server welcome message,
# request and store CAPABILITY response.
if __debug__:
if self.debug >= 1:
_mesg('
new
IMAP4
connection
,
tag
=%
s
' % self.tagpre)
if __debug__:
if self.debug >= 1:
_mesg('
new
IMAP4
connection
,
tag
=%
s
' % self.tagpre)
self.welcome = self._get_response()
if self.untagged_responses.has_key('
PREAUTH
'):
self.state = '
AUTH
'
elif self.untagged_responses.has_key('
OK
'):
self.state = '
NONAUTH
'
else:
raise self.error(self.welcome)
self.welcome = self._get_response()
if self.untagged_responses.has_key('
PREAUTH
'):
self.state = '
AUTH
'
elif self.untagged_responses.has_key('
OK
'):
self.state = '
NONAUTH
'
else:
raise self.error(self.welcome)
cap = '
CAPABILITY
'
self._simple_command(cap)
if not self.untagged_responses.has_key(cap):
raise self.error('
no
CAPABILITY
response
from
server
')
self.capabilities = tuple(string.split(string.upper(self.untagged_responses[cap][-1])))
cap = '
CAPABILITY
'
self._simple_command(cap)
if not self.untagged_responses.has_key(cap):
raise self.error('
no
CAPABILITY
response
from
server
')
self.capabilities = tuple(string.split(string.upper(self.untagged_responses[cap][-1])))
if __debug__:
if self.debug >= 3:
_mesg('
CAPABILITIES
:
%
s
' % `self.capabilities`)
if __debug__:
if self.debug >= 3:
_mesg('
CAPABILITIES
:
%
s
' % `self.capabilities`)
for version in AllowedVersions:
if not version in self.capabilities:
continue
self.PROTOCOL_VERSION = version
return
for version in AllowedVersions:
if not version in self.capabilities:
continue
self.PROTOCOL_VERSION = version
return
raise self.error('
server
not
IMAP4
compliant
')
raise self.error('
server
not
IMAP4
compliant
')
def __getattr__(self, attr):
#
Allow UPPERCASE variants of IMAP4 command methods.
if Commands.has_key(attr):
return eval("self.%s" % string.lower(attr))
raise AttributeError("Unknown IMAP4 command: '
%
s
'" % attr)
def __getattr__(self, attr):
#
Allow UPPERCASE variants of IMAP4 command methods.
if Commands.has_key(attr):
return eval("self.%s" % string.lower(attr))
raise AttributeError("Unknown IMAP4 command: '
%
s
'" % attr)
#
Public methods
#
Public methods
def open(self, host, port):
"""Setup '
self
.
sock
' and '
self
.
file
'."""
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((self.host, self.port))
self.file = self.sock.makefile('r')
def open(self, host, port):
"""Setup '
self
.
sock
' and '
self
.
file
'."""
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((self.host, self.port))
self.file = self.sock.makefile('r')
def recent(self):
"""Return most recent '
RECENT
' responses if any exist,
else prompt server for an update using the '
NOOP
' command.
def recent(self):
"""Return most recent '
RECENT
' responses if any exist,
else prompt server for an update using the '
NOOP
' command.
(typ, [data]) = <instance>.recent()
(typ, [data]) = <instance>.recent()
'
data
' is None if no new messages,
else list of RECENT responses, most recent last.
"""
name = '
RECENT
'
typ, dat = self._untagged_response('
OK
', [None], name)
if dat[-1]:
return typ, dat
typ, dat = self.noop()
# Prod server for response
return self._untagged_response(typ, dat, name)
'
data
' is None if no new messages,
else list of RECENT responses, most recent last.
"""
name = '
RECENT
'
typ, dat = self._untagged_response('
OK
', [None], name)
if dat[-1]:
return typ, dat
typ, dat = self.noop()
# Prod server for response
return self._untagged_response(typ, dat, name)
def response(self, code):
"""Return data for response '
code
' if received, or None.
def response(self, code):
"""Return data for response '
code
' if received, or None.
Old value for response '
code
' is cleared.
Old value for response '
code
' is cleared.
(code, [data]) = <instance>.response(code)
"""
return self._untagged_response(code, [None], string.upper(code))
(code, [data]) = <instance>.response(code)
"""
return self._untagged_response(code, [None], string.upper(code))
def socket(self):
"""Return socket instance used to connect to IMAP4 server.
def socket(self):
"""Return socket instance used to connect to IMAP4 server.
socket = <instance>.socket()
"""
return self.sock
socket = <instance>.socket()
"""
return self.sock
#
IMAP4 commands
#
IMAP4 commands
def append(self, mailbox, flags, date_time, message):
"""Append message to named mailbox.
def append(self, mailbox, flags, date_time, message):
"""Append message to named mailbox.
(typ, [data]) = <instance>.append(mailbox, flags, date_time, message)
(typ, [data]) = <instance>.append(mailbox, flags, date_time, message)
All args except `message'
can
be
None
.
"""
name = 'APPEND'
if not mailbox:
mailbox = 'INBOX'
if flags:
if (flags[0],flags[-1]) != ('(',')'):
flags = '(%s)' % flags
else:
flags = None
if date_time:
date_time = Time2Internaldate(date_time)
else:
date_time = None
self.literal = message
return self._simple_command(name, mailbox, flags, date_time)
All args except `message'
can
be
None
.
"""
name = 'APPEND'
if not mailbox:
mailbox = 'INBOX'
if flags:
if (flags[0],flags[-1]) != ('(',')'):
flags = '(%s)' % flags
else:
flags = None
if date_time:
date_time = Time2Internaldate(date_time)
else:
date_time = None
self.literal = message
return self._simple_command(name, mailbox, flags, date_time)
def authenticate(self, mechanism, authobject):
"""
Authenticate
command
-
requires
response
processing
.
def authenticate(self, mechanism, authobject):
"""
Authenticate
command
-
requires
response
processing
.
'mechanism'
specifies
which
authentication
mechanism
is
to
be
used
-
it
must
appear
in
<
instance
>
.
capabilities
in
the
form
AUTH
=<
mechanism
>
.
'mechanism'
specifies
which
authentication
mechanism
is
to
be
used
-
it
must
appear
in
<
instance
>
.
capabilities
in
the
form
AUTH
=<
mechanism
>
.
'authobject'
must
be
a
callable
object
:
'authobject'
must
be
a
callable
object
:
data
=
authobject
(
response
)
data
=
authobject
(
response
)
It
will
be
called
to
process
server
continuation
responses
.
It
should
return
data
that
will
be
encoded
and
sent
to
server
.
It
should
return
None
if
the
client
abort
response
'*'
should
be
sent
instead
.
"""
mech = string.upper(mechanism)
cap = 'AUTH=%s' % mech
if not cap in self.capabilities:
raise self.error("Server doesn't allow %s authentication." % mech)
self.literal = _Authenticator(authobject).process
typ, dat = self._simple_command('AUTHENTICATE', mech)
if typ != 'OK':
raise self.error(dat[-1])
self.state = 'AUTH'
return typ, dat
It
will
be
called
to
process
server
continuation
responses
.
It
should
return
data
that
will
be
encoded
and
sent
to
server
.
It
should
return
None
if
the
client
abort
response
'*'
should
be
sent
instead
.
"""
mech = string.upper(mechanism)
cap = 'AUTH=%s' % mech
if not cap in self.capabilities:
raise self.error("Server doesn't allow %s authentication." % mech)
self.literal = _Authenticator(authobject).process
typ, dat = self._simple_command('AUTHENTICATE', mech)
if typ != 'OK':
raise self.error(dat[-1])
self.state = 'AUTH'
return typ, dat
def check(self):
"""
Checkpoint
mailbox
on
server
.
def check(self):
"""
Checkpoint
mailbox
on
server
.
(
typ
,
[
data
])
=
<
instance
>
.
check
()
"""
return self._simple_command('CHECK')
(
typ
,
[
data
])
=
<
instance
>
.
check
()
"""
return self._simple_command('CHECK')
def close(self):
"""
Close
currently
selected
mailbox
.
def close(self):
"""
Close
currently
selected
mailbox
.
Deleted
messages
are
removed
from
writable
mailbox
.
This
is
the
recommended
command
before
'LOGOUT'
.
Deleted
messages
are
removed
from
writable
mailbox
.
This
is
the
recommended
command
before
'LOGOUT'
.
(
typ
,
[
data
])
=
<
instance
>
.
close
()
"""
try:
typ, dat = self._simple_command('CLOSE')
finally:
self.state = 'AUTH'
return typ, dat
(
typ
,
[
data
])
=
<
instance
>
.
close
()
"""
try:
typ, dat = self._simple_command('CLOSE')
finally:
self.state = 'AUTH'
return typ, dat
def copy(self, message_set, new_mailbox):
"""
Copy
'message_set'
messages
onto
end
of
'new_mailbox'
.
def copy(self, message_set, new_mailbox):
"""
Copy
'message_set'
messages
onto
end
of
'new_mailbox'
.
(
typ
,
[
data
])
=
<
instance
>
.
copy
(
message_set
,
new_mailbox
)
"""
return self._simple_command('COPY', message_set, new_mailbox)
(
typ
,
[
data
])
=
<
instance
>
.
copy
(
message_set
,
new_mailbox
)
"""
return self._simple_command('COPY', message_set, new_mailbox)
def create(self, mailbox):
"""
Create
new
mailbox
.
def create(self, mailbox):
"""
Create
new
mailbox
.
(
typ
,
[
data
])
=
<
instance
>
.
create
(
mailbox
)
"""
return self._simple_command('CREATE', mailbox)
(
typ
,
[
data
])
=
<
instance
>
.
create
(
mailbox
)
"""
return self._simple_command('CREATE', mailbox)
def delete(self, mailbox):
"""
Delete
old
mailbox
.
def delete(self, mailbox):
"""
Delete
old
mailbox
.
(
typ
,
[
data
])
=
<
instance
>
.
delete
(
mailbox
)
"""
return self._simple_command('DELETE', mailbox)
(
typ
,
[
data
])
=
<
instance
>
.
delete
(
mailbox
)
"""
return self._simple_command('DELETE', mailbox)
def expunge(self):
"""
Permanently
remove
deleted
items
from
selected
mailbox
.
def expunge(self):
"""
Permanently
remove
deleted
items
from
selected
mailbox
.
Generates
'EXPUNGE'
response
for
each
deleted
message
.
Generates
'EXPUNGE'
response
for
each
deleted
message
.
(
typ
,
[
data
])
=
<
instance
>
.
expunge
()
(
typ
,
[
data
])
=
<
instance
>
.
expunge
()
'data'
is
list
of
'EXPUNGE'
d
message
numbers
in
order
received
.
"""
name = 'EXPUNGE'
typ, dat = self._simple_command(name)
return self._untagged_response(typ, dat, name)
'data'
is
list
of
'EXPUNGE'
d
message
numbers
in
order
received
.
"""
name = 'EXPUNGE'
typ, dat = self._simple_command(name)
return self._untagged_response(typ, dat, name)
def fetch(self, message_set, message_parts):
"""
Fetch
(
parts
of
)
messages
.
def fetch(self, message_set, message_parts):
"""
Fetch
(
parts
of
)
messages
.
(
typ
,
[
data
,
...])
=
<
instance
>
.
fetch
(
message_set
,
message_parts
)
(
typ
,
[
data
,
...])
=
<
instance
>
.
fetch
(
message_set
,
message_parts
)
'message_parts'
should
be
a
string
of
selected
parts
enclosed
in
parentheses
,
eg
:
"(UID BODY[TEXT])"
.
'message_parts'
should
be
a
string
of
selected
parts
enclosed
in
parentheses
,
eg
:
"(UID BODY[TEXT])"
.
'data'
are
tuples
of
message
part
envelope
and
data
.
"""
name = 'FETCH'
typ, dat = self._simple_command(name, message_set, message_parts)
return self._untagged_response(typ, dat, name)
'data'
are
tuples
of
message
part
envelope
and
data
.
"""
name = 'FETCH'
typ, dat = self._simple_command(name, message_set, message_parts)
return self._untagged_response(typ, dat, name)
def list(self, directory='""', pattern='*'):
"""
List
mailbox
names
in
directory
matching
pattern
.
def list(self, directory='""', pattern='*'):
"""
List
mailbox
names
in
directory
matching
pattern
.
(
typ
,
[
data
])
=
<
instance
>
.
list
(
directory
=
'""'
,
pattern
=
'*'
)
(
typ
,
[
data
])
=
<
instance
>
.
list
(
directory
=
'""'
,
pattern
=
'*'
)
'data'
is
list
of
LIST
responses
.
"""
name = 'LIST'
typ, dat = self._simple_command(name, directory, pattern)
return self._untagged_response(typ, dat, name)
'data'
is
list
of
LIST
responses
.
"""
name = 'LIST'
typ, dat = self._simple_command(name, directory, pattern)
return self._untagged_response(typ, dat, name)
def login(self, user, password):
"""
Identify
client
using
plaintext
password
.
def login(self, user, password):
"""
Identify
client
using
plaintext
password
.
(
typ
,
[
data
])
=
<
instance
>
.
login
(
user
,
password
)
(
typ
,
[
data
])
=
<
instance
>
.
login
(
user
,
password
)
NB
:
'password'
will
be
quoted
.
"""
#if not 'AUTH=LOGIN' in self.capabilities:
#
raise self.error("Server doesn't allow LOGIN authentication." % mech)
typ, dat = self._simple_command('LOGIN', user, self._quote(password))
if typ != 'OK':
raise self.error(dat[-1])
self.state = 'AUTH'
return typ, dat
NB
:
'password'
will
be
quoted
.
"""
#if not 'AUTH=LOGIN' in self.capabilities:
#
raise self.error("Server doesn't allow LOGIN authentication." % mech)
typ, dat = self._simple_command('LOGIN', user, self._quote(password))
if typ != 'OK':
raise self.error(dat[-1])
self.state = 'AUTH'
return typ, dat
def logout(self):
"""
Shutdown
connection
to
server
.
def logout(self):
"""
Shutdown
connection
to
server
.
(
typ
,
[
data
])
=
<
instance
>
.
logout
()
(
typ
,
[
data
])
=
<
instance
>
.
logout
()
Returns
server
'BYE'
response
.
"""
self.state = 'LOGOUT'
try: typ, dat = self._simple_command('LOGOUT')
except: typ, dat = 'NO', ['%s: %s' % sys.exc_info()[:2]]
self.file.close()
self.sock.close()
if self.untagged_responses.has_key('BYE'):
return 'BYE', self.untagged_responses['BYE']
return typ, dat
Returns
server
'BYE'
response
.
"""
self.state = 'LOGOUT'
try: typ, dat = self._simple_command('LOGOUT')
except: typ, dat = 'NO', ['%s: %s' % sys.exc_info()[:2]]
self.file.close()
self.sock.close()
if self.untagged_responses.has_key('BYE'):
return 'BYE', self.untagged_responses['BYE']
return typ, dat
def lsub(self, directory='""', pattern='*'):
"""
List
'subscribed'
mailbox
names
in
directory
matching
pattern
.
def lsub(self, directory='""', pattern='*'):
"""
List
'subscribed'
mailbox
names
in
directory
matching
pattern
.
(
typ
,
[
data
,
...])
=
<
instance
>
.
lsub
(
directory
=
'""'
,
pattern
=
'*'
)
(
typ
,
[
data
,
...])
=
<
instance
>
.
lsub
(
directory
=
'""'
,
pattern
=
'*'
)
'data'
are
tuples
of
message
part
envelope
and
data
.
"""
name = 'LSUB'
typ, dat = self._simple_command(name, directory, pattern)
return self._untagged_response(typ, dat, name)
'data'
are
tuples
of
message
part
envelope
and
data
.
"""
name = 'LSUB'
typ, dat = self._simple_command(name, directory, pattern)
return self._untagged_response(typ, dat, name)
def noop(self):
"""
Send
NOOP
command
.
def noop(self):
"""
Send
NOOP
command
.
(
typ
,
data
)
=
<
instance
>
.
noop
()
"""
if __debug__:
if self.debug >= 3:
_dump_ur(self.untagged_responses)
return self._simple_command('NOOP')
(
typ
,
data
)
=
<
instance
>
.
noop
()
"""
if __debug__:
if self.debug >= 3:
_dump_ur(self.untagged_responses)
return self._simple_command('NOOP')
def partial(self, message_num, message_part, start, length):
"""
Fetch
truncated
part
of
a
message
.
def partial(self, message_num, message_part, start, length):
"""
Fetch
truncated
part
of
a
message
.
(
typ
,
[
data
,
...])
=
<
instance
>
.
partial
(
message_num
,
message_part
,
start
,
length
)
(
typ
,
[
data
,
...])
=
<
instance
>
.
partial
(
message_num
,
message_part
,
start
,
length
)
'data'
is
tuple
of
message
part
envelope
and
data
.
"""
name = 'PARTIAL'
typ, dat = self._simple_command(name, message_num, message_part, start, length)
return self._untagged_response(typ, dat, 'FETCH')
'data'
is
tuple
of
message
part
envelope
and
data
.
"""
name = 'PARTIAL'
typ, dat = self._simple_command(name, message_num, message_part, start, length)
return self._untagged_response(typ, dat, 'FETCH')
def rename(self, oldmailbox, newmailbox):
"""
Rename
old
mailbox
name
to
new
.
def rename(self, oldmailbox, newmailbox):
"""
Rename
old
mailbox
name
to
new
.
(
typ
,
data
)
=
<
instance
>
.
rename
(
oldmailbox
,
newmailbox
)
"""
return self._simple_command('RENAME', oldmailbox, newmailbox)
(
typ
,
data
)
=
<
instance
>
.
rename
(
oldmailbox
,
newmailbox
)
"""
return self._simple_command('RENAME', oldmailbox, newmailbox)
def search(self, charset, *criteria):
"""
Search
mailbox
for
matching
messages
.
def search(self, charset, *criteria):
"""
Search
mailbox
for
matching
messages
.
(
typ
,
[
data
])
=
<
instance
>
.
search
(
charset
,
criterium
,
...)
(
typ
,
[
data
])
=
<
instance
>
.
search
(
charset
,
criterium
,
...)
'data'
is
space
separated
list
of
matching
message
numbers
.
"""
name = 'SEARCH'
if charset:
charset = 'CHARSET ' + charset
typ, dat = apply(self._simple_command, (name, charset) + criteria)
return self._untagged_response(typ, dat, name)
'data'
is
space
separated
list
of
matching
message
numbers
.
"""
name = 'SEARCH'
if charset:
charset = 'CHARSET ' + charset
typ, dat = apply(self._simple_command, (name, charset) + criteria)
return self._untagged_response(typ, dat, name)
def select(self, mailbox='INBOX', readonly=None):
"""
Select
a
mailbox
.
def select(self, mailbox='INBOX', readonly=None):
"""
Select
a
mailbox
.
Flush
all
untagged
responses
.
Flush
all
untagged
responses
.
(
typ
,
[
data
])
=
<
instance
>
.
select
(
mailbox
=
'INBOX'
,
readonly
=
None
)
(
typ
,
[
data
])
=
<
instance
>
.
select
(
mailbox
=
'INBOX'
,
readonly
=
None
)
'data'
is
count
of
messages
in
mailbox
(
'EXISTS'
response
).
"""
# Mandated responses are ('FLAGS', 'EXISTS', 'RECENT', 'UIDVALIDITY')
self.untagged_responses = {}
# Flush old responses.
self.is_readonly = readonly
if readonly:
name = 'EXAMINE'
else:
name = 'SELECT'
typ, dat = self._simple_command(name, mailbox)
if typ != 'OK':
self.state = 'AUTH'
# Might have been 'SELECTED'
return typ, dat
self.state = 'SELECTED'
if self.untagged_responses.has_key('READ-ONLY')
\
and not readonly:
if __debug__:
if self.debug >= 1:
_dump_ur(self.untagged_responses)
raise self.readonly('%s is not writable' % mailbox)
return typ, self.untagged_responses.get('EXISTS', [None])
'data'
is
count
of
messages
in
mailbox
(
'EXISTS'
response
).
"""
# Mandated responses are ('FLAGS', 'EXISTS', 'RECENT', 'UIDVALIDITY')
self.untagged_responses = {}
# Flush old responses.
self.is_readonly = readonly
if readonly:
name = 'EXAMINE'
else:
name = 'SELECT'
typ, dat = self._simple_command(name, mailbox)
if typ != 'OK':
self.state = 'AUTH'
# Might have been 'SELECTED'
return typ, dat
self.state = 'SELECTED'
if self.untagged_responses.has_key('READ-ONLY')
\
and not readonly:
if __debug__:
if self.debug >= 1:
_dump_ur(self.untagged_responses)
raise self.readonly('%s is not writable' % mailbox)
return typ, self.untagged_responses.get('EXISTS', [None])
def status(self, mailbox, names):
"""
Request
named
status
conditions
for
mailbox
.
def status(self, mailbox, names):
"""
Request
named
status
conditions
for
mailbox
.
(
typ
,
[
data
])
=
<
instance
>
.
status
(
mailbox
,
names
)
"""
name = 'STATUS'
if self.PROTOCOL_VERSION == 'IMAP4':
raise self.error('%s unimplemented in IMAP4 (obtain IMAP4rev1 server, or re-code)' % name)
typ, dat = self._simple_command(name, mailbox, names)
return self._untagged_response(typ, dat, name)
(
typ
,
[
data
])
=
<
instance
>
.
status
(
mailbox
,
names
)
"""
name = 'STATUS'
if self.PROTOCOL_VERSION == 'IMAP4':
raise self.error('%s unimplemented in IMAP4 (obtain IMAP4rev1 server, or re-code)' % name)
typ, dat = self._simple_command(name, mailbox, names)
return self._untagged_response(typ, dat, name)
def store(self, message_set, command, flags):
"""
Alters
flag
dispositions
for
messages
in
mailbox
.
def store(self, message_set, command, flags):
"""
Alters
flag
dispositions
for
messages
in
mailbox
.
(
typ
,
[
data
])
=
<
instance
>
.
store
(
message_set
,
command
,
flags
)
"""
if (flags[0],flags[-1]) != ('(',')'):
flags = '(%s)' % flags
# Avoid quoting the flags
typ, dat = self._simple_command('STORE', message_set, command, flags)
return self._untagged_response(typ, dat, 'FETCH')
(
typ
,
[
data
])
=
<
instance
>
.
store
(
message_set
,
command
,
flags
)
"""
if (flags[0],flags[-1]) != ('(',')'):
flags = '(%s)' % flags
# Avoid quoting the flags
typ, dat = self._simple_command('STORE', message_set, command, flags)
return self._untagged_response(typ, dat, 'FETCH')
def subscribe(self, mailbox):
"""
Subscribe
to
new
mailbox
.
def subscribe(self, mailbox):
"""
Subscribe
to
new
mailbox
.
(
typ
,
[
data
])
=
<
instance
>
.
subscribe
(
mailbox
)
"""
return self._simple_command('SUBSCRIBE', mailbox)
(
typ
,
[
data
])
=
<
instance
>
.
subscribe
(
mailbox
)
"""
return self._simple_command('SUBSCRIBE', mailbox)
def uid(self, command, *args):
"""
Execute
"command arg ..."
with
messages
identified
by
UID
,
rather
than
message
number
.
def uid(self, command, *args):
"""
Execute
"command arg ..."
with
messages
identified
by
UID
,
rather
than
message
number
.
(
typ
,
[
data
])
=
<
instance
>
.
uid
(
command
,
arg1
,
arg2
,
...)
(
typ
,
[
data
])
=
<
instance
>
.
uid
(
command
,
arg1
,
arg2
,
...)
Returns
response
appropriate
to
'command'
.
"""
command = string.upper(command)
if not Commands.has_key(command):
raise self.error("Unknown IMAP4 UID command: %s" % command)
if self.state not in Commands[command]:
raise self.error('command %s illegal in state %s'
% (command, self.state))
name = 'UID'
typ, dat = apply(self._simple_command, (name, command) + args)
if command == 'SEARCH':
name = 'SEARCH'
else:
name = 'FETCH'
return self._untagged_response(typ, dat, name)
Returns
response
appropriate
to
'command'
.
"""
command = string.upper(command)
if not Commands.has_key(command):
raise self.error("Unknown IMAP4 UID command: %s" % command)
if self.state not in Commands[command]:
raise self.error('command %s illegal in state %s'
% (command, self.state))
name = 'UID'
typ, dat = apply(self._simple_command, (name, command) + args)
if command == 'SEARCH':
name = 'SEARCH'
else:
name = 'FETCH'
return self._untagged_response(typ, dat, name)
def unsubscribe(self, mailbox):
"""
Unsubscribe
from
old
mailbox
.
def unsubscribe(self, mailbox):
"""
Unsubscribe
from
old
mailbox
.
(
typ
,
[
data
])
=
<
instance
>
.
unsubscribe
(
mailbox
)
"""
return self._simple_command('UNSUBSCRIBE', mailbox)
def xatom(self, name, *args):
"""
Allow
simple
extension
commands
notified
by
server
in
CAPABILITY
response
.
(
typ
,
[
data
])
=
<
instance
>
.
unsubscribe
(
mailbox
)
"""
return self._simple_command('UNSUBSCRIBE', mailbox)
def xatom(self, name, *args):
"""
Allow
simple
extension
commands
notified
by
server
in
CAPABILITY
response
.
(
typ
,
[
data
])
=
<
instance
>
.
xatom
(
name
,
arg
,
...)
"""
if name[0] != 'X' or not name in self.capabilities:
raise self.error('unknown extension command: %s' % name)
return apply(self._simple_command, (name,) + args)
(
typ
,
[
data
])
=
<
instance
>
.
xatom
(
name
,
arg
,
...)
"""
if name[0] != 'X' or not name in self.capabilities:
raise self.error('unknown extension command: %s' % name)
return apply(self._simple_command, (name,) + args)
#
Private methods
def _append_untagged(self, typ, dat):
if dat is None: dat = ''
ur = self.untagged_responses
if __debug__:
if self.debug >= 5:
_mesg('untagged_responses[%s] %s += ["%s"]' %
(typ, len(ur.get(typ,'')), dat))
if ur.has_key(typ):
ur[typ].append(dat)
else:
ur[typ] = [dat]
#
Private methods
def _append_untagged(self, typ, dat):
if dat is None: dat = ''
ur = self.untagged_responses
if __debug__:
if self.debug >= 5:
_mesg('untagged_responses[%s] %s += ["%s"]' %
(typ, len(ur.get(typ,'')), dat))
if ur.has_key(typ):
ur[typ].append(dat)
else:
ur[typ] = [dat]
def _check_bye(self):
bye = self.untagged_responses.get('BYE')
if bye:
raise self.abort(bye[-1])
def _check_bye(self):
bye = self.untagged_responses.get('BYE')
if bye:
raise self.abort(bye[-1])
def _command(self, name, *args):
def _command(self, name, *args):
if self.state not in Commands[name]:
self.literal = None
raise self.error(
'command %s illegal in state %s' % (name, self.state))
if self.state not in Commands[name]:
self.literal = None
raise self.error(
'command %s illegal in state %s' % (name, self.state))
for typ in ('OK', 'NO', 'BAD'):
if self.untagged_responses.has_key(typ):
del self.untagged_responses[typ]
for typ in ('OK', 'NO', 'BAD'):
if self.untagged_responses.has_key(typ):
del self.untagged_responses[typ]
if self.untagged_responses.has_key('READ-ONLY')
\
and not self.is_readonly:
raise self.readonly('mailbox status changed to READ-ONLY')
if self.untagged_responses.has_key('READ-ONLY')
\
and not self.is_readonly:
raise self.readonly('mailbox status changed to READ-ONLY')
tag = self._new_tag()
data = '%s %s' % (tag, name)
for arg in args:
if arg is None: continue
data = '%s %s' % (data, self._checkquote(arg))
tag = self._new_tag()
data = '%s %s' % (tag, name)
for arg in args:
if arg is None: continue
data = '%s %s' % (data, self._checkquote(arg))
literal = self.literal
if literal is not None:
self.literal = None
if type(literal) is type(self._command):
literator = literal
else:
literator = None
data = '%s {%s}' % (data, len(literal))
literal = self.literal
if literal is not None:
self.literal = None
if type(literal) is type(self._command):
literator = literal
else:
literator = None
data = '%s {%s}' % (data, len(literal))
if __debug__:
if self.debug >= 4:
_mesg('> %s' % data)
else:
_log('> %s' % data)
if __debug__:
if self.debug >= 4:
_mesg('> %s' % data)
else:
_log('> %s' % data)
try:
self.sock.send('%s%s' % (data, CRLF))
except socket.error, val:
raise self.abort('socket error: %s' % val)
try:
self.sock.send('%s%s' % (data, CRLF))
except socket.error, val:
raise self.abort('socket error: %s' % val)
if literal is None:
return tag
if literal is None:
return tag
while 1:
# Wait for continuation response
while 1:
# Wait for continuation response
while self._get_response():
if self.tagged_commands[tag]:
# BAD/NO?
return tag
while self._get_response():
if self.tagged_commands[tag]:
# BAD/NO?
return tag
# Send literal
# Send literal
if literator:
literal = literator(self.continuation_response)
if literator:
literal = literator(self.continuation_response)
if __debug__:
if self.debug >= 4:
_mesg('write literal size %s' % len(literal))
if __debug__:
if self.debug >= 4:
_mesg('write literal size %s' % len(literal))
try:
self.sock.send(literal)
self.sock.send(CRLF)
except socket.error, val:
raise self.abort('socket error: %s' % val)
try:
self.sock.send(literal)
self.sock.send(CRLF)
except socket.error, val:
raise self.abort('socket error: %s' % val)
if not literator:
break
if not literator:
break
return tag
return tag
def _command_complete(self, name, tag):
self._check_bye()
try:
typ, data = self._get_tagged_response(tag)
except self.abort, val:
raise self.abort('command: %s => %s' % (name, val))
except self.error, val:
raise self.error('command: %s => %s' % (name, val))
self._check_bye()
if typ == 'BAD':
raise self.error('%s command error: %s %s' % (name, typ, data))
return typ, data
def _command_complete(self, name, tag):
self._check_bye()
try:
typ, data = self._get_tagged_response(tag)
except self.abort, val:
raise self.abort('command: %s => %s' % (name, val))
except self.error, val:
raise self.error('command: %s => %s' % (name, val))
self._check_bye()
if typ == 'BAD':
raise self.error('%s command error: %s %s' % (name, typ, data))
return typ, data
def _get_response(self):
def _get_response(self):
# Read response and store.
#
# Returns None for continuation responses,
# otherwise first response line received.
# Read response and store.
#
# Returns None for continuation responses,
# otherwise first response line received.
resp = self._get_line()
resp = self._get_line()
# Command completion response?
# Command completion response?
if self._match(self.tagre, resp):
tag = self.mo.group('tag')
if not self.tagged_commands.has_key(tag):
raise self.abort('unexpected tagged response: %s' % resp)
if self._match(self.tagre, resp):
tag = self.mo.group('tag')
if not self.tagged_commands.has_key(tag):
raise self.abort('unexpected tagged response: %s' % resp)
typ = self.mo.group('type')
dat = self.mo.group('data')
self.tagged_commands[tag] = (typ, [dat])
else:
dat2 = None
typ = self.mo.group('type')
dat = self.mo.group('data')
self.tagged_commands[tag] = (typ, [dat])
else:
dat2 = None
# '*' (untagged) responses?
# '*' (untagged) responses?
if not self._match(Untagged_response, resp):
if self._match(Untagged_status, resp):
dat2 = self.mo.group('data2')
if not self._match(Untagged_response, resp):
if self._match(Untagged_status, resp):
dat2 = self.mo.group('data2')
if self.mo is None:
# Only other possibility is '+' (continuation) response...
if self.mo is None:
# Only other possibility is '+' (continuation) response...
if self._match(Continuation, resp):
self.continuation_response = self.mo.group('data')
return None
# NB: indicates continuation
if self._match(Continuation, resp):
self.continuation_response = self.mo.group('data')
return None
# NB: indicates continuation
raise self.abort("unexpected response: '%s'" % resp)
raise self.abort("unexpected response: '%s'" % resp)
typ = self.mo.group('type')
dat = self.mo.group('data')
if dat is None: dat = ''
# Null untagged response
if dat2: dat = dat + ' ' + dat2
typ = self.mo.group('type')
dat = self.mo.group('data')
if dat is None: dat = ''
# Null untagged response
if dat2: dat = dat + ' ' + dat2
# Is there a literal to come?
# Is there a literal to come?
while self._match(Literal, dat):
while self._match(Literal, dat):
# Read literal direct from connection.
# Read literal direct from connection.
size = string.atoi(self.mo.group('size'))
if __debug__:
if self.debug >= 4:
_mesg('read literal size %s' % size)
data = self.file.read(size)
size = string.atoi(self.mo.group('size'))
if __debug__:
if self.debug >= 4:
_mesg('read literal size %s' % size)
data = self.file.read(size)
# Store response with literal as tuple
# Store response with literal as tuple
self._append_untagged(typ, (dat, data))
self._append_untagged(typ, (dat, data))
# Read trailer - possibly containing another literal
# Read trailer - possibly containing another literal
dat = self._get_line()
dat = self._get_line()
self._append_untagged(typ, dat)
self._append_untagged(typ, dat)
# Bracketed response information?
# Bracketed response information?
if typ in ('OK', 'NO', 'BAD') and self._match(Response_code, dat):
self._append_untagged(self.mo.group('type'), self.mo.group('data'))
if typ in ('OK', 'NO', 'BAD') and self._match(Response_code, dat):
self._append_untagged(self.mo.group('type'), self.mo.group('data'))
if __debug__:
if self.debug >= 1 and typ in ('NO', 'BAD', 'BYE'):
_mesg('%s response: %s' % (typ, dat))
if __debug__:
if self.debug >= 1 and typ in ('NO', 'BAD', 'BYE'):
_mesg('%s response: %s' % (typ, dat))
return resp
return resp
def _get_tagged_response(self, tag):
def _get_tagged_response(self, tag):
while 1:
result = self.tagged_commands[tag]
if result is not None:
del self.tagged_commands[tag]
return result
while 1:
result = self.tagged_commands[tag]
if result is not None:
del self.tagged_commands[tag]
return result
# Some have reported "unexpected response" exceptions.
# Note that ignoring them here causes loops.
# Instead, send me details of the unexpected response and
# I'll update the code in `_get_response()'.
# Some have reported "unexpected response" exceptions.
# Note that ignoring them here causes loops.
# Instead, send me details of the unexpected response and
# I'll update the code in `_get_response()'.
try:
self._get_response()
except self.abort, val:
if __debug__:
if self.debug >= 1:
print_log()
raise
try:
self._get_response()
except self.abort, val:
if __debug__:
if self.debug >= 1:
print_log()
raise
def _get_line(self):
def _get_line(self):
line = self.file.readline()
if not line:
raise self.abort('socket error: EOF')
line = self.file.readline()
if not line:
raise self.abort('socket error: EOF')
# Protocol mandates all lines terminated by CRLF
# Protocol mandates all lines terminated by CRLF
line = line[:-2]
if __debug__:
if self.debug >= 4:
_mesg('< %s' % line)
else:
_log('< %s' % line)
return line
line = line[:-2]
if __debug__:
if self.debug >= 4:
_mesg('< %s' % line)
else:
_log('< %s' % line)
return line
def _match(self, cre, s):
def _match(self, cre, s):
# Run compiled regular expression match method on 's'.
# Save result, return success.
# Run compiled regular expression match method on 's'.
# Save result, return success.
self.mo = cre.match(s)
if __debug__:
if self.mo is not None and self.debug >= 5:
_mesg("
\
t
matched r'%s' => %s" % (cre.pattern, `self.mo.groups()`))
return self.mo is not None
self.mo = cre.match(s)
if __debug__:
if self.mo is not None and self.debug >= 5:
_mesg("
\
t
matched r'%s' => %s" % (cre.pattern, `self.mo.groups()`))
return self.mo is not None
def _new_tag(self):
def _new_tag(self):
tag = '%s%s' % (self.tagpre, self.tagnum)
self.tagnum = self.tagnum + 1
self.tagged_commands[tag] = None
return tag
tag = '%s%s' % (self.tagpre, self.tagnum)
self.tagnum = self.tagnum + 1
self.tagged_commands[tag] = None
return tag
def _checkquote(self, arg):
def _checkquote(self, arg):
# Must quote command args if non-alphanumeric chars present,
# and not already quoted.
# Must quote command args if non-alphanumeric chars present,
# and not already quoted.
if type(arg) is not type(''):
return arg
if (arg[0],arg[-1]) in (('(',')'),('"','"')):
return arg
if self.mustquote.search(arg) is None:
return arg
return self._quote(arg)
if type(arg) is not type(''):
return arg
if (arg[0],arg[-1]) in (('(',')'),('"','"')):
return arg
if self.mustquote.search(arg) is None:
return arg
return self._quote(arg)
def _quote(self, arg):
def _quote(self, arg):
arg = string.replace(arg, '
\
\
', '
\
\
\
\
')
arg = string.replace(arg, '"', '
\
\
"')
arg = string.replace(arg, '
\
\
', '
\
\
\
\
')
arg = string.replace(arg, '"', '
\
\
"')
return '"%s"' % arg
return '"%s"' % arg
def _simple_command(self, name, *args):
def _simple_command(self, name, *args):
return self._command_complete(name, apply(self._command, (name,) + args))
return self._command_complete(name, apply(self._command, (name,) + args))
def _untagged_response(self, typ, dat, name):
def _untagged_response(self, typ, dat, name):
if typ == 'NO':
return typ, dat
if not self.untagged_responses.has_key(name):
return typ, [None]
data = self.untagged_responses[name]
if __debug__:
if self.debug >= 5:
_mesg('untagged_responses[%s] => %s' % (name, data))
del self.untagged_responses[name]
return typ, data
if typ == 'NO':
return typ, dat
if not self.untagged_responses.has_key(name):
return typ, [None]
data = self.untagged_responses[name]
if __debug__:
if self.debug >= 5:
_mesg('untagged_responses[%s] => %s' % (name, data))
del self.untagged_responses[name]
return typ, data
class _Authenticator:
"""
Private
class
to
provide
en
/
decoding
for
base64
-
based
authentication
conversation
.
"""
def __init__(self, mechinst):
self.mech = mechinst
# Callable object to provide/process data
def process(self, data):
ret = self.mech(self.decode(data))
if ret is None:
return '*'
# Abort conversation
return self.encode(ret)
def encode(self, inp):
#
# Invoke binascii.b2a_base64 iteratively with
# short even length buffers, strip the trailing
# line feed from the result and append. "Even"
# means a number that factors to both 6 and 8,
# so when it gets to the end of the 8-bit input
# there's no partial 6-bit output.
#
oup = ''
while inp:
if len(inp) > 48:
t = inp[:48]
inp = inp[48:]
else:
t = inp
inp = ''
e = binascii.b2a_base64(t)
if e:
oup = oup + e[:-1]
return oup
def decode(self, inp):
if not inp:
return ''
return binascii.a2b_base64(inp)
"""
Private
class
to
provide
en
/
decoding
for
base64
-
based
authentication
conversation
.
"""
def __init__(self, mechinst):
self.mech = mechinst
# Callable object to provide/process data
def process(self, data):
ret = self.mech(self.decode(data))
if ret is None:
return '*'
# Abort conversation
return self.encode(ret)
def encode(self, inp):
#
# Invoke binascii.b2a_base64 iteratively with
# short even length buffers, strip the trailing
# line feed from the result and append. "Even"
# means a number that factors to both 6 and 8,
# so when it gets to the end of the 8-bit input
# there's no partial 6-bit output.
#
oup = ''
while inp:
if len(inp) > 48:
t = inp[:48]
inp = inp[48:]
else:
t = inp
inp = ''
e = binascii.b2a_base64(t)
if e:
oup = oup + e[:-1]
return oup
def decode(self, inp):
if not inp:
return ''
return binascii.a2b_base64(inp)
Mon2num = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
def Internaldate2tuple(resp):
"""
Convert
IMAP4
INTERNALDATE
to
UT
.
"""
Convert
IMAP4
INTERNALDATE
to
UT
.
Returns
Python
time
module
tuple
.
"""
Returns
Python
time
module
tuple
.
"""
mo = InternalDate.match(resp)
if not mo:
return None
mo = InternalDate.match(resp)
if not mo:
return None
mon = Mon2num[mo.group('mon')]
zonen = mo.group('zonen')
mon = Mon2num[mo.group('mon')]
zonen = mo.group('zonen')
for name in ('day', 'year', 'hour', 'min', 'sec', 'zoneh', 'zonem'):
exec "%s = string.atoi(mo.group('%s'))" % (name, name)
for name in ('day', 'year', 'hour', 'min', 'sec', 'zoneh', 'zonem'):
exec "%s = string.atoi(mo.group('%s'))" % (name, name)
# INTERNALDATE timezone must be subtracted to get UT
# INTERNALDATE timezone must be subtracted to get UT
zone = (zoneh*60 + zonem)*60
if zonen == '-':
zone = -zone
zone = (zoneh*60 + zonem)*60
if zonen == '-':
zone = -zone
tt = (year, mon, day, hour, min, sec, -1, -1, -1)
tt = (year, mon, day, hour, min, sec, -1, -1, -1)
utc = time.mktime(tt)
utc = time.mktime(tt)
# Following is necessary because the time module has no 'mkgmtime'.
# 'mktime' assumes arg in local timezone, so adds timezone/altzone.
# Following is necessary because the time module has no 'mkgmtime'.
# 'mktime' assumes arg in local timezone, so adds timezone/altzone.
lt = time.localtime(utc)
if time.daylight and lt[-1]:
zone = zone + time.altzone
else:
zone = zone + time.timezone
lt = time.localtime(utc)
if time.daylight and lt[-1]:
zone = zone + time.altzone
else:
zone = zone + time.timezone
return time.localtime(utc - zone)
return time.localtime(utc - zone)
def Int2AP(num):
"""
Convert
integer
to
A
-
P
string
representation
.
"""
"""
Convert
integer
to
A
-
P
string
representation
.
"""
val = ''; AP = 'ABCDEFGHIJKLMNOP'
num = int(abs(num))
while num:
num, mod = divmod(num, 16)
val = AP[mod] + val
return val
val = ''; AP = 'ABCDEFGHIJKLMNOP'
num = int(abs(num))
while num:
num, mod = divmod(num, 16)
val = AP[mod] + val
return val
def ParseFlags(resp):
"""
Convert
IMAP4
flags
response
to
python
tuple
.
"""
"""
Convert
IMAP4
flags
response
to
python
tuple
.
"""
mo = Flags.match(resp)
if not mo:
return ()
mo = Flags.match(resp)
if not mo:
return ()
return tuple(string.split(mo.group('flags')))
return tuple(string.split(mo.group('flags')))
def Time2Internaldate(date_time):
"""
Convert
'date_time'
to
IMAP4
INTERNALDATE
representation
.
"""
Convert
'date_time'
to
IMAP4
INTERNALDATE
representation
.
Return
string
in
form
:
'"DD-Mmm-YYYY HH:MM:SS +HHMM"'
"""
Return
string
in
form
:
'"DD-Mmm-YYYY HH:MM:SS +HHMM"'
"""
dttype = type(date_time)
if dttype is type(1) or dttype is type(1.1):
tt = time.localtime(date_time)
elif dttype is type(()):
tt = date_time
elif dttype is type(""):
return date_time
# Assume in correct format
else: raise ValueError
dttype = type(date_time)
if dttype is type(1) or dttype is type(1.1):
tt = time.localtime(date_time)
elif dttype is type(()):
tt = date_time
elif dttype is type(""):
return date_time
# Assume in correct format
else: raise ValueError
dt = time.strftime("%d-%b-%Y %H:%M:%S", tt)
if dt[0] == '0':
dt = ' ' + dt[1:]
if time.daylight and tt[-1]:
zone = -time.altzone
else:
zone = -time.timezone
return '"' + dt + " %+02d%02d" % divmod(zone/60, 60) + '"'
dt = time.strftime("%d-%b-%Y %H:%M:%S", tt)
if dt[0] == '0':
dt = ' ' + dt[1:]
if time.daylight and tt[-1]:
zone = -time.altzone
else:
zone = -time.timezone
return '"' + dt + " %+02d%02d" % divmod(zone/60, 60) + '"'
if __debug__:
def _mesg(s, secs=None):
if secs is None:
secs = time.time()
tm = time.strftime('%M:%S', time.localtime(secs))
sys.stderr.write(' %s.%02d %s
\
n
' % (tm, (secs*100)%100, s))
sys.stderr.flush()
def _mesg(s, secs=None):
if secs is None:
secs = time.time()
tm = time.strftime('%M:%S', time.localtime(secs))
sys.stderr.write(' %s.%02d %s
\
n
' % (tm, (secs*100)%100, s))
sys.stderr.flush()
def _dump_ur(dict):
# Dump untagged responses (in `dict').
l = dict.items()
if not l: return
t = '
\
n
\
t
\
t
'
j = string.join
l = map(lambda x,j=j:'%s: "%s"' % (x[0], x[1][0] and j(x[1], '" "') or ''), l)
_mesg('untagged responses dump:%s%s' % (t, j(l, t)))
def _dump_ur(dict):
# Dump untagged responses (in `dict').
l = dict.items()
if not l: return
t = '
\
n
\
t
\
t
'
j = string.join
l = map(lambda x,j=j:'%s: "%s"' % (x[0], x[1][0] and j(x[1], '" "') or ''), l)
_mesg('untagged responses dump:%s%s' % (t, j(l, t)))
_cmd_log = []
# Last `_cmd_log_len' interactions
_cmd_log_len = 10
_cmd_log = []
# Last `_cmd_log_len' interactions
_cmd_log_len = 10
def _log(line):
# Keep log of last `_cmd_log_len' interactions for debugging.
if len(_cmd_log) == _cmd_log_len:
del _cmd_log[0]
_cmd_log.append((time.time(), line))
def _log(line):
# Keep log of last `_cmd_log_len' interactions for debugging.
if len(_cmd_log) == _cmd_log_len:
del _cmd_log[0]
_cmd_log.append((time.time(), line))
def print_log():
_mesg('last %d IMAP4 interactions:' % len(_cmd_log))
for secs,line in _cmd_log:
_mesg(line, secs)
def print_log():
_mesg('last %d IMAP4 interactions:' % len(_cmd_log))
for secs,line in _cmd_log:
_mesg(line, secs)
if __name__ == '__main__':
import getopt, getpass, sys
try:
optlist, args = getopt.getopt(sys.argv[1:], 'd:')
except getopt.error, val:
pass
for opt,val in optlist:
if opt == '-d':
Debug = int(val)
if not args: args = ('',)
host = args[0]
USER = getpass.getuser()
PASSWD = getpass.getpass("IMAP password for %s on %s" % (USER, host or "localhost"))
test_mesg = 'From: %s@localhost
\
n
Subject: IMAP4 test
\
n
\
n
data...
\
n
' % USER
test_seq1 = (
('login', (USER, PASSWD)),
('create', ('/tmp/xxx 1',)),
('rename', ('/tmp/xxx 1', '/tmp/yyy')),
('CREATE', ('/tmp/yyz 2',)),
('append', ('/tmp/yyz 2', None, None, test_mesg)),
('list', ('/tmp', 'yy*')),
('select', ('/tmp/yyz 2',)),
('search', (None, 'SUBJECT', 'test')),
('partial', ('1', 'RFC822', 1, 1024)),
('store', ('1', 'FLAGS', '(
\
Dele
t
ed)')),
('expunge', ()),
('recent', ()),
('close', ()),
)
test_seq2 = (
('select', ()),
('response',('UIDVALIDITY',)),
('uid', ('SEARCH', 'ALL')),
('response', ('EXISTS',)),
('append', (None, None, None, test_mesg)),
('recent', ()),
('logout', ()),
)
def run(cmd, args):
_mesg('%s %s' % (cmd, args))
typ, dat = apply(eval('M.%s' % cmd), args)
_mesg('%s => %s %s' % (cmd, typ, dat))
return dat
try:
M = IMAP4(host)
_mesg('PROTOCOL_VERSION = %s' % M.PROTOCOL_VERSION)
for cmd,args in test_seq1:
run(cmd, args)
for ml in run('list', ('/tmp/', 'yy%')):
mo = re.match(r'.*"([^"]+)"$', ml)
if mo: path = mo.group(1)
else: path = string.split(ml)[-1]
run('delete', (path,))
for cmd,args in test_seq2:
dat = run(cmd, args)
if (cmd,args) != ('uid', ('SEARCH', 'ALL')):
continue
uid = string.split(dat[-1])
if not uid: continue
run('uid', ('FETCH', '%s' % uid[-1],
'(FLAGS INTERNALDATE RFC822.SIZE RFC822.HEADER RFC822.TEXT)'))
print '
\
n
All tests OK.'
except:
print '
\
n
Tests failed.'
if not Debug:
print '''
import getopt, getpass, sys
try:
optlist, args = getopt.getopt(sys.argv[1:], 'd:')
except getopt.error, val:
pass
for opt,val in optlist:
if opt == '-d':
Debug = int(val)
if not args: args = ('',)
host = args[0]
USER = getpass.getuser()
PASSWD = getpass.getpass("IMAP password for %s on %s" % (USER, host or "localhost"))
test_mesg = 'From: %s@localhost
\
n
Subject: IMAP4 test
\
n
\
n
data...
\
n
' % USER
test_seq1 = (
('login', (USER, PASSWD)),
('create', ('/tmp/xxx 1',)),
('rename', ('/tmp/xxx 1', '/tmp/yyy')),
('CREATE', ('/tmp/yyz 2',)),
('append', ('/tmp/yyz 2', None, None, test_mesg)),
('list', ('/tmp', 'yy*')),
('select', ('/tmp/yyz 2',)),
('search', (None, 'SUBJECT', 'test')),
('partial', ('1', 'RFC822', 1, 1024)),
('store', ('1', 'FLAGS', '(
\
Dele
t
ed)')),
('expunge', ()),
('recent', ()),
('close', ()),
)
test_seq2 = (
('select', ()),
('response',('UIDVALIDITY',)),
('uid', ('SEARCH', 'ALL')),
('response', ('EXISTS',)),
('append', (None, None, None, test_mesg)),
('recent', ()),
('logout', ()),
)
def run(cmd, args):
_mesg('%s %s' % (cmd, args))
typ, dat = apply(eval('M.%s' % cmd), args)
_mesg('%s => %s %s' % (cmd, typ, dat))
return dat
try:
M = IMAP4(host)
_mesg('PROTOCOL_VERSION = %s' % M.PROTOCOL_VERSION)
for cmd,args in test_seq1:
run(cmd, args)
for ml in run('list', ('/tmp/', 'yy%')):
mo = re.match(r'.*"([^"]+)"$', ml)
if mo: path = mo.group(1)
else: path = string.split(ml)[-1]
run('delete', (path,))
for cmd,args in test_seq2:
dat = run(cmd, args)
if (cmd,args) != ('uid', ('SEARCH', 'ALL')):
continue
uid = string.split(dat[-1])
if not uid: continue
run('uid', ('FETCH', '%s' % uid[-1],
'(FLAGS INTERNALDATE RFC822.SIZE RFC822.HEADER RFC822.TEXT)'))
print '
\
n
All tests OK.'
except:
print '
\
n
Tests failed.'
if not Debug:
print '''
If you would like to see debugging output,
try: %s -d5
''' % sys.argv[0]
raise
raise
Lib/imghdr.py
View file @
463a4d72
...
...
@@ -14,7 +14,7 @@ def what(file, h=None):
location
=
file
.
tell
()
h
=
file
.
read
(
32
)
file
.
seek
(
location
)
f
=
None
f
=
None
else
:
f
=
None
try
:
...
...
@@ -103,7 +103,7 @@ tests.append(test_jpeg)
def
test_bmp
(
h
,
f
):
if
h
[:
2
]
==
'BM'
:
return
'bmp'
tests
.
append
(
test_bmp
)
def
test_png
(
h
,
f
):
...
...
Lib/imputil.py
View file @
463a4d72
...
...
@@ -5,7 +5,7 @@
### docco needed here and in Docs/ ...
# note: avoid importing non-builtin modules
import
imp
### not available in JPython?
import
imp
### not available in JPython?
import
sys
import
strop
import
__builtin__
...
...
@@ -15,7 +15,7 @@ import struct
import
marshal
_StringType
=
type
(
''
)
_ModuleType
=
type
(
sys
)
### doesn't work in JPython...
_ModuleType
=
type
(
sys
)
### doesn't work in JPython...
class
ImportManager
:
"Manage the import process."
...
...
@@ -663,7 +663,7 @@ def _test_revamp():
#
#
# Guido's comments on sys.path caching:
#
#
# We could cache this in a dictionary: the ImportManager can have a
# cache dict mapping pathnames to importer objects, and a separate
# method for coming up with an importer given a pathname that's not yet
...
...
@@ -679,16 +679,16 @@ def _test_revamp():
# My/Guido's comments on factoring ImportManager and Importer:
#
# > However, we still have a tension occurring here:
# >
# >
# > 1) implementing policy in ImportManager assists in single-point policy
# > changes for app/rexec situations
# > 2) implementing policy in Importer assists in package-private policy
# > changes for normal, operating conditions
# >
# >
# > I'll see if I can sort out a way to do this. Maybe the Importer class will
# > implement the methods (which can be overridden to change policy) by
# > delegating to ImportManager.
#
#
# Maybe also think about what kind of policies an Importer would be
# likely to want to change. I have a feeling that a lot of the code
# there is actually not so much policy but a *necessity* to get things
...
...
Lib/macurl2path.py
View file @
463a4d72
...
...
@@ -16,7 +16,7 @@ def url2pathname(pathname):
raise
RuntimeError
,
'Cannot convert non-local URL to pathname'
# Turn starting /// into /, an empty hostname means current host
if
pathname
[:
3
]
==
'///'
:
pathname
=
pathname
[
2
:]
pathname
=
pathname
[
2
:]
elif
pathname
[:
2
]
==
'//'
:
raise
RuntimeError
,
'Cannot convert non-local URL to pathname'
components
=
string
.
split
(
pathname
,
'/'
)
...
...
@@ -68,11 +68,11 @@ def pathname2url(pathname):
return
'/'
+
string
.
join
(
components
,
'/'
)
else
:
return
string
.
join
(
components
,
'/'
)
def
_pncomp2url
(
component
):
component
=
urllib
.
quote
(
component
[:
31
],
safe
=
''
)
# We want to quote slashes
return
component
component
=
urllib
.
quote
(
component
[:
31
],
safe
=
''
)
# We want to quote slashes
return
component
def
test
():
for
url
in
[
"index.html"
,
"bar/index.html"
,
...
...
Lib/mailcap.py
View file @
463a4d72
...
...
@@ -8,7 +8,7 @@ import string
def
getcaps
():
"""Return a dictionary containing the mailcap database.
The dictionary maps a MIME type (in all lowercase, e.g. 'text/plain')
to a list of dictionaries corresponding to mailcap entries. The list
collects all the entries for that MIME type from all available mailcap
...
...
@@ -137,7 +137,7 @@ def parsefield(line, i, n):
def
findmatch
(
caps
,
MIMEtype
,
key
=
'view'
,
filename
=
"/dev/null"
,
plist
=
[]):
"""Find a match for a mailcap entry.
Return a tuple containing the command line, and the mailcap entry
used; (None, None) if no match is found. This may invoke the
'test' command of several matching entries before deciding which
...
...
@@ -145,7 +145,7 @@ def findmatch(caps, MIMEtype, key='view', filename="/dev/null", plist=[]):
"""
entries
=
lookup
(
caps
,
MIMEtype
,
key
)
# XXX This code should somehow check for the needsterminal flag.
# XXX This code should somehow check for the needsterminal flag.
for
e
in
entries
:
if
e
.
has_key
(
'test'
):
test
=
subst
(
e
[
'test'
],
filename
,
plist
)
...
...
Lib/mimetools.py
View file @
463a4d72
...
...
@@ -7,85 +7,85 @@ import tempfile
class
Message
(
rfc822
.
Message
):
"""A derived class of rfc822.Message that knows about MIME headers and
contains some hooks for decoding encoded and multipart messages."""
def
__init__
(
self
,
fp
,
seekable
=
1
):
rfc822
.
Message
.
__init__
(
self
,
fp
,
seekable
)
self
.
encodingheader
=
\
self
.
getheader
(
'content-transfer-encoding'
)
self
.
typeheader
=
\
self
.
getheader
(
'content-type'
)
self
.
parsetype
()
self
.
parseplist
()
def
parsetype
(
self
):
str
=
self
.
typeheader
if
str
is
None
:
str
=
'text/plain'
if
';'
in
str
:
i
=
str
.
index
(
';'
)
self
.
plisttext
=
str
[
i
:]
str
=
str
[:
i
]
else
:
self
.
plisttext
=
''
fields
=
str
.
split
(
'/'
)
for
i
in
range
(
len
(
fields
)):
fields
[
i
]
=
fields
[
i
].
strip
().
lower
()
self
.
type
=
'/'
.
join
(
fields
)
self
.
maintype
=
fields
[
0
]
self
.
subtype
=
'/'
.
join
(
fields
[
1
:])
def
parseplist
(
self
):
str
=
self
.
plisttext
self
.
plist
=
[]
while
str
[:
1
]
==
';'
:
str
=
str
[
1
:]
if
';'
in
str
:
# XXX Should parse quotes!
end
=
str
.
index
(
';'
)
else
:
end
=
len
(
str
)
f
=
str
[:
end
]
if
'='
in
f
:
i
=
f
.
index
(
'='
)
f
=
f
[:
i
].
strip
().
lower
()
+
\
'='
+
f
[
i
+
1
:].
strip
()
self
.
plist
.
append
(
f
.
strip
())
str
=
str
[
end
:]
def
getplist
(
self
):
return
self
.
plist
def
getparam
(
self
,
name
):
name
=
name
.
lower
()
+
'='
n
=
len
(
name
)
for
p
in
self
.
plist
:
if
p
[:
n
]
==
name
:
return
rfc822
.
unquote
(
p
[
n
:])
return
None
def
getparamnames
(
self
):
result
=
[]
for
p
in
self
.
plist
:
i
=
p
.
find
(
'='
)
if
i
>=
0
:
result
.
append
(
p
[:
i
].
lower
())
return
result
def
getencoding
(
self
):
if
self
.
encodingheader
is
None
:
return
'7bit'
return
self
.
encodingheader
.
lower
()
def
gettype
(
self
):
return
self
.
type
def
getmaintype
(
self
):
return
self
.
maintype
def
getsubtype
(
self
):
return
self
.
subtype
"""A derived class of rfc822.Message that knows about MIME headers and
contains some hooks for decoding encoded and multipart messages."""
def
__init__
(
self
,
fp
,
seekable
=
1
):
rfc822
.
Message
.
__init__
(
self
,
fp
,
seekable
)
self
.
encodingheader
=
\
self
.
getheader
(
'content-transfer-encoding'
)
self
.
typeheader
=
\
self
.
getheader
(
'content-type'
)
self
.
parsetype
()
self
.
parseplist
()
def
parsetype
(
self
):
str
=
self
.
typeheader
if
str
is
None
:
str
=
'text/plain'
if
';'
in
str
:
i
=
str
.
index
(
';'
)
self
.
plisttext
=
str
[
i
:]
str
=
str
[:
i
]
else
:
self
.
plisttext
=
''
fields
=
str
.
split
(
'/'
)
for
i
in
range
(
len
(
fields
)):
fields
[
i
]
=
fields
[
i
].
strip
().
lower
()
self
.
type
=
'/'
.
join
(
fields
)
self
.
maintype
=
fields
[
0
]
self
.
subtype
=
'/'
.
join
(
fields
[
1
:])
def
parseplist
(
self
):
str
=
self
.
plisttext
self
.
plist
=
[]
while
str
[:
1
]
==
';'
:
str
=
str
[
1
:]
if
';'
in
str
:
# XXX Should parse quotes!
end
=
str
.
index
(
';'
)
else
:
end
=
len
(
str
)
f
=
str
[:
end
]
if
'='
in
f
:
i
=
f
.
index
(
'='
)
f
=
f
[:
i
].
strip
().
lower
()
+
\
'='
+
f
[
i
+
1
:].
strip
()
self
.
plist
.
append
(
f
.
strip
())
str
=
str
[
end
:]
def
getplist
(
self
):
return
self
.
plist
def
getparam
(
self
,
name
):
name
=
name
.
lower
()
+
'='
n
=
len
(
name
)
for
p
in
self
.
plist
:
if
p
[:
n
]
==
name
:
return
rfc822
.
unquote
(
p
[
n
:])
return
None
def
getparamnames
(
self
):
result
=
[]
for
p
in
self
.
plist
:
i
=
p
.
find
(
'='
)
if
i
>=
0
:
result
.
append
(
p
[:
i
].
lower
())
return
result
def
getencoding
(
self
):
if
self
.
encodingheader
is
None
:
return
'7bit'
return
self
.
encodingheader
.
lower
()
def
gettype
(
self
):
return
self
.
type
def
getmaintype
(
self
):
return
self
.
maintype
def
getsubtype
(
self
):
return
self
.
subtype
...
...
@@ -97,74 +97,74 @@ class Message(rfc822.Message):
_prefix
=
None
def
choose_boundary
():
"""Return a random string usable as a multipart boundary.
The method used is so that it is *very* unlikely that the same
string of characters will every occur again in the Universe,
so the caller needn't check the data it is packing for the
occurrence of the boundary.
The boundary contains dots so you have to quote it in the header."""
global
_prefix
import
time
import
random
if
_prefix
is
None
:
import
socket
import
os
hostid
=
socket
.
gethostbyname
(
socket
.
gethostname
())
try
:
uid
=
`os.getuid()`
except
:
uid
=
'1'
try
:
pid
=
`os.getpid()`
except
:
pid
=
'1'
_prefix
=
hostid
+
'.'
+
uid
+
'.'
+
pid
timestamp
=
'%.3f'
%
time
.
time
()
seed
=
`random.randint(0, 32767)`
return
_prefix
+
'.'
+
timestamp
+
'.'
+
seed
"""Return a random string usable as a multipart boundary.
The method used is so that it is *very* unlikely that the same
string of characters will every occur again in the Universe,
so the caller needn't check the data it is packing for the
occurrence of the boundary.
The boundary contains dots so you have to quote it in the header."""
global
_prefix
import
time
import
random
if
_prefix
is
None
:
import
socket
import
os
hostid
=
socket
.
gethostbyname
(
socket
.
gethostname
())
try
:
uid
=
`os.getuid()`
except
:
uid
=
'1'
try
:
pid
=
`os.getpid()`
except
:
pid
=
'1'
_prefix
=
hostid
+
'.'
+
uid
+
'.'
+
pid
timestamp
=
'%.3f'
%
time
.
time
()
seed
=
`random.randint(0, 32767)`
return
_prefix
+
'.'
+
timestamp
+
'.'
+
seed
# Subroutines for decoding some common content-transfer-types
def
decode
(
input
,
output
,
encoding
):
"""Decode common content-transfer-encodings (base64, quopri, uuencode)."""
if
encoding
==
'base64'
:
import
base64
return
base64
.
decode
(
input
,
output
)
if
encoding
==
'quoted-printable'
:
import
quopri
return
quopri
.
decode
(
input
,
output
)
if
encoding
in
(
'uuencode'
,
'x-uuencode'
,
'uue'
,
'x-uue'
):
import
uu
return
uu
.
decode
(
input
,
output
)
if
encoding
in
(
'7bit'
,
'8bit'
):
return
output
.
write
(
input
.
read
())
if
decodetab
.
has_key
(
encoding
):
pipethrough
(
input
,
decodetab
[
encoding
],
output
)
else
:
raise
ValueError
,
\
'unknown Content-Transfer-Encoding: %s'
%
encoding
"""Decode common content-transfer-encodings (base64, quopri, uuencode)."""
if
encoding
==
'base64'
:
import
base64
return
base64
.
decode
(
input
,
output
)
if
encoding
==
'quoted-printable'
:
import
quopri
return
quopri
.
decode
(
input
,
output
)
if
encoding
in
(
'uuencode'
,
'x-uuencode'
,
'uue'
,
'x-uue'
):
import
uu
return
uu
.
decode
(
input
,
output
)
if
encoding
in
(
'7bit'
,
'8bit'
):
return
output
.
write
(
input
.
read
())
if
decodetab
.
has_key
(
encoding
):
pipethrough
(
input
,
decodetab
[
encoding
],
output
)
else
:
raise
ValueError
,
\
'unknown Content-Transfer-Encoding: %s'
%
encoding
def
encode
(
input
,
output
,
encoding
):
"""Encode common content-transfer-encodings (base64, quopri, uuencode)."""
if
encoding
==
'base64'
:
import
base64
return
base64
.
encode
(
input
,
output
)
if
encoding
==
'quoted-printable'
:
import
quopri
return
quopri
.
encode
(
input
,
output
,
0
)
if
encoding
in
(
'uuencode'
,
'x-uuencode'
,
'uue'
,
'x-uue'
):
import
uu
return
uu
.
encode
(
input
,
output
)
if
encoding
in
(
'7bit'
,
'8bit'
):
return
output
.
write
(
input
.
read
())
if
encodetab
.
has_key
(
encoding
):
pipethrough
(
input
,
encodetab
[
encoding
],
output
)
else
:
raise
ValueError
,
\
'unknown Content-Transfer-Encoding: %s'
%
encoding
"""Encode common content-transfer-encodings (base64, quopri, uuencode)."""
if
encoding
==
'base64'
:
import
base64
return
base64
.
encode
(
input
,
output
)
if
encoding
==
'quoted-printable'
:
import
quopri
return
quopri
.
encode
(
input
,
output
,
0
)
if
encoding
in
(
'uuencode'
,
'x-uuencode'
,
'uue'
,
'x-uue'
):
import
uu
return
uu
.
encode
(
input
,
output
)
if
encoding
in
(
'7bit'
,
'8bit'
):
return
output
.
write
(
input
.
read
())
if
encodetab
.
has_key
(
encoding
):
pipethrough
(
input
,
encodetab
[
encoding
],
output
)
else
:
raise
ValueError
,
\
'unknown Content-Transfer-Encoding: %s'
%
encoding
# The following is no longer used for standard encodings
...
...
@@ -178,51 +178,51 @@ rm $TEMP
)'''
decodetab
=
{
'uuencode'
:
uudecode_pipe
,
'x-uuencode'
:
uudecode_pipe
,
'uue'
:
uudecode_pipe
,
'x-uue'
:
uudecode_pipe
,
'quoted-printable'
:
'mmencode -u -q'
,
'base64'
:
'mmencode -u -b'
,
'uuencode'
:
uudecode_pipe
,
'x-uuencode'
:
uudecode_pipe
,
'uue'
:
uudecode_pipe
,
'x-uue'
:
uudecode_pipe
,
'quoted-printable'
:
'mmencode -u -q'
,
'base64'
:
'mmencode -u -b'
,
}
encodetab
=
{
'x-uuencode'
:
'uuencode tempfile'
,
'uuencode'
:
'uuencode tempfile'
,
'x-uue'
:
'uuencode tempfile'
,
'uue'
:
'uuencode tempfile'
,
'quoted-printable'
:
'mmencode -q'
,
'base64'
:
'mmencode -b'
,
'x-uuencode'
:
'uuencode tempfile'
,
'uuencode'
:
'uuencode tempfile'
,
'x-uue'
:
'uuencode tempfile'
,
'uue'
:
'uuencode tempfile'
,
'quoted-printable'
:
'mmencode -q'
,
'base64'
:
'mmencode -b'
,
}
def
pipeto
(
input
,
command
):
pipe
=
os
.
popen
(
command
,
'w'
)
copyliteral
(
input
,
pipe
)
pipe
.
close
()
pipe
=
os
.
popen
(
command
,
'w'
)
copyliteral
(
input
,
pipe
)
pipe
.
close
()
def
pipethrough
(
input
,
command
,
output
):
tempname
=
tempfile
.
mktemp
()
try
:
temp
=
open
(
tempname
,
'w'
)
except
IOError
:
print
'*** Cannot create temp file'
,
`tempname`
return
copyliteral
(
input
,
temp
)
temp
.
close
()
pipe
=
os
.
popen
(
command
+
' <'
+
tempname
,
'r'
)
copybinary
(
pipe
,
output
)
pipe
.
close
()
os
.
unlink
(
tempname
)
tempname
=
tempfile
.
mktemp
()
try
:
temp
=
open
(
tempname
,
'w'
)
except
IOError
:
print
'*** Cannot create temp file'
,
`tempname`
return
copyliteral
(
input
,
temp
)
temp
.
close
()
pipe
=
os
.
popen
(
command
+
' <'
+
tempname
,
'r'
)
copybinary
(
pipe
,
output
)
pipe
.
close
()
os
.
unlink
(
tempname
)
def
copyliteral
(
input
,
output
):
while
1
:
line
=
input
.
readline
()
if
not
line
:
break
output
.
write
(
line
)
while
1
:
line
=
input
.
readline
()
if
not
line
:
break
output
.
write
(
line
)
def
copybinary
(
input
,
output
):
BUFSIZE
=
8192
while
1
:
line
=
input
.
read
(
BUFSIZE
)
if
not
line
:
break
output
.
write
(
line
)
BUFSIZE
=
8192
while
1
:
line
=
input
.
read
(
BUFSIZE
)
if
not
line
:
break
output
.
write
(
line
)
Lib/mimify.py
View file @
463a4d72
...
...
@@ -6,8 +6,8 @@ Decode quoted-printable parts of a mail message or encode using
quoted-printable.
Usage:
mimify(input, output)
unmimify(input, output, decode_base64 = 0)
mimify(input, output)
unmimify(input, output, decode_base64 = 0)
to encode and decode respectively. Input and output may be the name
of a file or an open file object. Only a readline() method is used
on the input file, only a write() method is used on the output file.
...
...
@@ -15,16 +15,16 @@ When using file names, the input and output file names may be the
same.
Interactive usage:
mimify.py -e [infile [outfile]]
mimify.py -d [infile [outfile]]
mimify.py -e [infile [outfile]]
mimify.py -d [infile [outfile]]
to encode and decode respectively. Infile defaults to standard
input and outfile to standard output.
"""
# Configure
MAXLEN
=
200
# if lines longer than this, encode as quoted-printable
CHARSET
=
'ISO-8859-1'
# default charset for non-US-ASCII mail
QUOTE
=
'> '
# string replies are quoted with
MAXLEN
=
200
# if lines longer than this, encode as quoted-printable
CHARSET
=
'ISO-8859-1'
# default charset for non-US-ASCII mail
QUOTE
=
'> '
# string replies are quoted with
# End configure
import
re
,
string
...
...
@@ -39,425 +39,424 @@ mime_head = re.compile('=\\?iso-8859-1\\?q\\?([^? \t\n]+)\\?=', re.I)
repl
=
re
.
compile
(
'^subject:
\
\
s+re: '
,
re
.
I
)
class
File
:
"""A simple fake file object that knows about limited read-ahead and
boundaries. The only supported method is readline()."""
def
__init__
(
self
,
file
,
boundary
):
self
.
file
=
file
self
.
boundary
=
boundary
self
.
peek
=
None
def
readline
(
self
):
if
self
.
peek
is
not
None
:
return
''
line
=
self
.
file
.
readline
()
if
not
line
:
return
line
if
self
.
boundary
:
if
line
==
self
.
boundary
+
'
\
n
'
:
self
.
peek
=
line
return
''
if
line
==
self
.
boundary
+
'--
\
n
'
:
self
.
peek
=
line
return
''
return
line
"""A simple fake file object that knows about limited read-ahead and
boundaries. The only supported method is readline()."""
def
__init__
(
self
,
file
,
boundary
):
self
.
file
=
file
self
.
boundary
=
boundary
self
.
peek
=
None
def
readline
(
self
):
if
self
.
peek
is
not
None
:
return
''
line
=
self
.
file
.
readline
()
if
not
line
:
return
line
if
self
.
boundary
:
if
line
==
self
.
boundary
+
'
\
n
'
:
self
.
peek
=
line
return
''
if
line
==
self
.
boundary
+
'--
\
n
'
:
self
.
peek
=
line
return
''
return
line
class
HeaderFile
:
def
__init__
(
self
,
file
):
self
.
file
=
file
self
.
peek
=
None
def
readline
(
self
):
if
self
.
peek
is
not
None
:
line
=
self
.
peek
self
.
peek
=
None
else
:
line
=
self
.
file
.
readline
()
if
not
line
:
return
line
if
he
.
match
(
line
):
return
line
while
1
:
self
.
peek
=
self
.
file
.
readline
()
if
len
(
self
.
peek
)
==
0
or
\
(
self
.
peek
[
0
]
!=
' '
and
self
.
peek
[
0
]
!=
'
\
t
'
):
return
line
line
=
line
+
self
.
peek
self
.
peek
=
None
def
__init__
(
self
,
file
):
self
.
file
=
file
self
.
peek
=
None
def
readline
(
self
):
if
self
.
peek
is
not
None
:
line
=
self
.
peek
self
.
peek
=
None
else
:
line
=
self
.
file
.
readline
()
if
not
line
:
return
line
if
he
.
match
(
line
):
return
line
while
1
:
self
.
peek
=
self
.
file
.
readline
()
if
len
(
self
.
peek
)
==
0
or
\
(
self
.
peek
[
0
]
!=
' '
and
self
.
peek
[
0
]
!=
'
\
t
'
):
return
line
line
=
line
+
self
.
peek
self
.
peek
=
None
def
mime_decode
(
line
):
"""Decode a single line of quoted-printable text to 8bit."""
newline
=
''
pos
=
0
while
1
:
res
=
mime_code
.
search
(
line
,
pos
)
if
res
is
None
:
break
newline
=
newline
+
line
[
pos
:
res
.
start
(
0
)]
+
\
chr
(
string
.
atoi
(
res
.
group
(
1
),
16
))
pos
=
res
.
end
(
0
)
return
newline
+
line
[
pos
:]
"""Decode a single line of quoted-printable text to 8bit."""
newline
=
''
pos
=
0
while
1
:
res
=
mime_code
.
search
(
line
,
pos
)
if
res
is
None
:
break
newline
=
newline
+
line
[
pos
:
res
.
start
(
0
)]
+
\
chr
(
string
.
atoi
(
res
.
group
(
1
),
16
))
pos
=
res
.
end
(
0
)
return
newline
+
line
[
pos
:]
def
mime_decode_header
(
line
):
"""Decode a header line to 8bit."""
newline
=
''
pos
=
0
while
1
:
res
=
mime_head
.
search
(
line
,
pos
)
if
res
is
None
:
break
match
=
res
.
group
(
1
)
# convert underscores to spaces (before =XX conversion!)
match
=
string
.
join
(
string
.
split
(
match
,
'_'
),
' '
)
newline
=
newline
+
line
[
pos
:
res
.
start
(
0
)]
+
mime_decode
(
match
)
pos
=
res
.
end
(
0
)
return
newline
+
line
[
pos
:]
"""Decode a header line to 8bit."""
newline
=
''
pos
=
0
while
1
:
res
=
mime_head
.
search
(
line
,
pos
)
if
res
is
None
:
break
match
=
res
.
group
(
1
)
# convert underscores to spaces (before =XX conversion!)
match
=
string
.
join
(
string
.
split
(
match
,
'_'
),
' '
)
newline
=
newline
+
line
[
pos
:
res
.
start
(
0
)]
+
mime_decode
(
match
)
pos
=
res
.
end
(
0
)
return
newline
+
line
[
pos
:]
def
unmimify_part
(
ifile
,
ofile
,
decode_base64
=
0
):
"""Convert a quoted-printable part of a MIME mail message to 8bit."""
multipart
=
None
quoted_printable
=
0
is_base64
=
0
is_repl
=
0
if
ifile
.
boundary
and
ifile
.
boundary
[:
2
]
==
QUOTE
:
prefix
=
QUOTE
else
:
prefix
=
''
# read header
hfile
=
HeaderFile
(
ifile
)
while
1
:
line
=
hfile
.
readline
()
if
not
line
:
return
if
prefix
and
line
[:
len
(
prefix
)]
==
prefix
:
line
=
line
[
len
(
prefix
):]
pref
=
prefix
else
:
pref
=
''
line
=
mime_decode_header
(
line
)
if
qp
.
match
(
line
):
quoted_printable
=
1
continue
# skip this header
if
decode_base64
and
base64_re
.
match
(
line
):
is_base64
=
1
continue
ofile
.
write
(
pref
+
line
)
if
not
prefix
and
repl
.
match
(
line
):
# we're dealing with a reply message
is_repl
=
1
mp_res
=
mp
.
match
(
line
)
if
mp_res
:
multipart
=
'--'
+
mp_res
.
group
(
1
)
if
he
.
match
(
line
):
break
if
is_repl
and
(
quoted_printable
or
multipart
):
is_repl
=
0
# read body
while
1
:
line
=
ifile
.
readline
()
if
not
line
:
return
line
=
re
.
sub
(
mime_head
,
'
\
\
1'
,
line
)
if
prefix
and
line
[:
len
(
prefix
)]
==
prefix
:
line
=
line
[
len
(
prefix
):]
pref
=
prefix
else
:
pref
=
''
##
if is_repl and len(line) >= 4 and line[:4] == QUOTE+'--' and line[-3:] != '--\n':
##
multipart = line[:-1]
while
multipart
:
if
line
==
multipart
+
'--
\
n
'
:
ofile
.
write
(
pref
+
line
)
multipart
=
None
line
=
None
break
if
line
==
multipart
+
'
\
n
'
:
ofile
.
write
(
pref
+
line
)
nifile
=
File
(
ifile
,
multipart
)
unmimify_part
(
nifile
,
ofile
,
decode_base64
)
line
=
nifile
.
peek
if
not
line
:
# premature end of file
break
continue
# not a boundary between parts
break
if
line
and
quoted_printable
:
while
line
[
-
2
:]
==
'=
\
n
'
:
line
=
line
[:
-
2
]
newline
=
ifile
.
readline
()
if
newline
[:
len
(
QUOTE
)]
==
QUOTE
:
newline
=
newline
[
len
(
QUOTE
):]
line
=
line
+
newline
line
=
mime_decode
(
line
)
if
line
and
is_base64
and
not
pref
:
import
base64
line
=
base64
.
decodestring
(
line
)
if
line
:
ofile
.
write
(
pref
+
line
)
"""Convert a quoted-printable part of a MIME mail message to 8bit."""
multipart
=
None
quoted_printable
=
0
is_base64
=
0
is_repl
=
0
if
ifile
.
boundary
and
ifile
.
boundary
[:
2
]
==
QUOTE
:
prefix
=
QUOTE
else
:
prefix
=
''
# read header
hfile
=
HeaderFile
(
ifile
)
while
1
:
line
=
hfile
.
readline
()
if
not
line
:
return
if
prefix
and
line
[:
len
(
prefix
)]
==
prefix
:
line
=
line
[
len
(
prefix
):]
pref
=
prefix
else
:
pref
=
''
line
=
mime_decode_header
(
line
)
if
qp
.
match
(
line
):
quoted_printable
=
1
continue
# skip this header
if
decode_base64
and
base64_re
.
match
(
line
):
is_base64
=
1
continue
ofile
.
write
(
pref
+
line
)
if
not
prefix
and
repl
.
match
(
line
):
# we're dealing with a reply message
is_repl
=
1
mp_res
=
mp
.
match
(
line
)
if
mp_res
:
multipart
=
'--'
+
mp_res
.
group
(
1
)
if
he
.
match
(
line
):
break
if
is_repl
and
(
quoted_printable
or
multipart
):
is_repl
=
0
# read body
while
1
:
line
=
ifile
.
readline
()
if
not
line
:
return
line
=
re
.
sub
(
mime_head
,
'
\
\
1'
,
line
)
if
prefix
and
line
[:
len
(
prefix
)]
==
prefix
:
line
=
line
[
len
(
prefix
):]
pref
=
prefix
else
:
pref
=
''
##
if is_repl and len(line) >= 4 and line[:4] == QUOTE+'--' and line[-3:] != '--\n':
##
multipart = line[:-1]
while
multipart
:
if
line
==
multipart
+
'--
\
n
'
:
ofile
.
write
(
pref
+
line
)
multipart
=
None
line
=
None
break
if
line
==
multipart
+
'
\
n
'
:
ofile
.
write
(
pref
+
line
)
nifile
=
File
(
ifile
,
multipart
)
unmimify_part
(
nifile
,
ofile
,
decode_base64
)
line
=
nifile
.
peek
if
not
line
:
# premature end of file
break
continue
# not a boundary between parts
break
if
line
and
quoted_printable
:
while
line
[
-
2
:]
==
'=
\
n
'
:
line
=
line
[:
-
2
]
newline
=
ifile
.
readline
()
if
newline
[:
len
(
QUOTE
)]
==
QUOTE
:
newline
=
newline
[
len
(
QUOTE
):]
line
=
line
+
newline
line
=
mime_decode
(
line
)
if
line
and
is_base64
and
not
pref
:
import
base64
line
=
base64
.
decodestring
(
line
)
if
line
:
ofile
.
write
(
pref
+
line
)
def
unmimify
(
infile
,
outfile
,
decode_base64
=
0
):
"""Convert quoted-printable parts of a MIME mail message to 8bit."""
if
type
(
infile
)
==
type
(
''
):
ifile
=
open
(
infile
)
if
type
(
outfile
)
==
type
(
''
)
and
infile
==
outfile
:
import
os
d
,
f
=
os
.
path
.
split
(
infile
)
os
.
rename
(
infile
,
os
.
path
.
join
(
d
,
','
+
f
))
else
:
ifile
=
infile
if
type
(
outfile
)
==
type
(
''
):
ofile
=
open
(
outfile
,
'w'
)
else
:
ofile
=
outfile
nifile
=
File
(
ifile
,
None
)
unmimify_part
(
nifile
,
ofile
,
decode_base64
)
ofile
.
flush
()
"""Convert quoted-printable parts of a MIME mail message to 8bit."""
if
type
(
infile
)
==
type
(
''
):
ifile
=
open
(
infile
)
if
type
(
outfile
)
==
type
(
''
)
and
infile
==
outfile
:
import
os
d
,
f
=
os
.
path
.
split
(
infile
)
os
.
rename
(
infile
,
os
.
path
.
join
(
d
,
','
+
f
))
else
:
ifile
=
infile
if
type
(
outfile
)
==
type
(
''
):
ofile
=
open
(
outfile
,
'w'
)
else
:
ofile
=
outfile
nifile
=
File
(
ifile
,
None
)
unmimify_part
(
nifile
,
ofile
,
decode_base64
)
ofile
.
flush
()
mime_char
=
re
.
compile
(
'[=
\
177
-
\
377
]'
)
# quote these chars in body
mime_header_char
=
re
.
compile
(
'[=?
\
177
-
\
377
]'
)
# quote these in header
def
mime_encode
(
line
,
header
):
"""Code a single line as quoted-printable.
If header is set, quote some extra characters."""
if
header
:
reg
=
mime_header_char
else
:
reg
=
mime_char
newline
=
''
pos
=
0
if
len
(
line
)
>=
5
and
line
[:
5
]
==
'From '
:
# quote 'From ' at the start of a line for stupid mailers
newline
=
string
.
upper
(
'=%02x'
%
ord
(
'F'
))
pos
=
1
while
1
:
res
=
reg
.
search
(
line
,
pos
)
if
res
is
None
:
break
newline
=
newline
+
line
[
pos
:
res
.
start
(
0
)]
+
\
string
.
upper
(
'=%02x'
%
ord
(
res
.
group
(
0
)))
pos
=
res
.
end
(
0
)
line
=
newline
+
line
[
pos
:]
newline
=
''
while
len
(
line
)
>=
75
:
i
=
73
while
line
[
i
]
==
'='
or
line
[
i
-
1
]
==
'='
:
i
=
i
-
1
i
=
i
+
1
newline
=
newline
+
line
[:
i
]
+
'=
\
n
'
line
=
line
[
i
:]
return
newline
+
line
"""Code a single line as quoted-printable.
If header is set, quote some extra characters."""
if
header
:
reg
=
mime_header_char
else
:
reg
=
mime_char
newline
=
''
pos
=
0
if
len
(
line
)
>=
5
and
line
[:
5
]
==
'From '
:
# quote 'From ' at the start of a line for stupid mailers
newline
=
string
.
upper
(
'=%02x'
%
ord
(
'F'
))
pos
=
1
while
1
:
res
=
reg
.
search
(
line
,
pos
)
if
res
is
None
:
break
newline
=
newline
+
line
[
pos
:
res
.
start
(
0
)]
+
\
string
.
upper
(
'=%02x'
%
ord
(
res
.
group
(
0
)))
pos
=
res
.
end
(
0
)
line
=
newline
+
line
[
pos
:]
newline
=
''
while
len
(
line
)
>=
75
:
i
=
73
while
line
[
i
]
==
'='
or
line
[
i
-
1
]
==
'='
:
i
=
i
-
1
i
=
i
+
1
newline
=
newline
+
line
[:
i
]
+
'=
\
n
'
line
=
line
[
i
:]
return
newline
+
line
mime_header
=
re
.
compile
(
'([
\
t
(]|^)([-a-zA-Z0-9_+]*[
\
177
-
\
377
][-a-zA-Z0-9_+
\
177
-
\
377
]*)([
\
t
)]|
\
n
)'
)
def
mime_encode_header
(
line
):
"""Code a single header line as quoted-printable."""
newline
=
''
pos
=
0
while
1
:
res
=
mime_header
.
search
(
line
,
pos
)
if
res
is
None
:
break
newline
=
'%s%s%s=?%s?Q?%s?=%s'
%
\
(
newline
,
line
[
pos
:
res
.
start
(
0
)],
res
.
group
(
1
),
CHARSET
,
mime_encode
(
res
.
group
(
2
),
1
),
res
.
group
(
3
))
pos
=
res
.
end
(
0
)
return
newline
+
line
[
pos
:]
"""Code a single header line as quoted-printable."""
newline
=
''
pos
=
0
while
1
:
res
=
mime_header
.
search
(
line
,
pos
)
if
res
is
None
:
break
newline
=
'%s%s%s=?%s?Q?%s?=%s'
%
\
(
newline
,
line
[
pos
:
res
.
start
(
0
)],
res
.
group
(
1
),
CHARSET
,
mime_encode
(
res
.
group
(
2
),
1
),
res
.
group
(
3
))
pos
=
res
.
end
(
0
)
return
newline
+
line
[
pos
:]
mv
=
re
.
compile
(
'^mime-version:'
,
re
.
I
)
cte
=
re
.
compile
(
'^content-transfer-encoding:'
,
re
.
I
)
iso_char
=
re
.
compile
(
'[
\
177
-
\
377
]'
)
def
mimify_part
(
ifile
,
ofile
,
is_mime
):
"""Convert an 8bit part of a MIME mail message to quoted-printable."""
has_cte
=
is_qp
=
is_base64
=
0
multipart
=
None
must_quote_body
=
must_quote_header
=
has_iso_chars
=
0
header
=
[]
header_end
=
''
message
=
[]
message_end
=
''
# read header
hfile
=
HeaderFile
(
ifile
)
while
1
:
line
=
hfile
.
readline
()
if
not
line
:
break
if
not
must_quote_header
and
iso_char
.
search
(
line
):
must_quote_header
=
1
if
mv
.
match
(
line
):
is_mime
=
1
if
cte
.
match
(
line
):
has_cte
=
1
if
qp
.
match
(
line
):
is_qp
=
1
elif
base64_re
.
match
(
line
):
is_base64
=
1
mp_res
=
mp
.
match
(
line
)
if
mp_res
:
multipart
=
'--'
+
mp_res
.
group
(
1
)
if
he
.
match
(
line
):
header_end
=
line
break
header
.
append
(
line
)
# read body
while
1
:
line
=
ifile
.
readline
()
if
not
line
:
break
if
multipart
:
if
line
==
multipart
+
'--
\
n
'
:
message_end
=
line
break
if
line
==
multipart
+
'
\
n
'
:
message_end
=
line
break
if
is_base64
:
message
.
append
(
line
)
continue
if
is_qp
:
while
line
[
-
2
:]
==
'=
\
n
'
:
line
=
line
[:
-
2
]
newline
=
ifile
.
readline
()
if
newline
[:
len
(
QUOTE
)]
==
QUOTE
:
newline
=
newline
[
len
(
QUOTE
):]
line
=
line
+
newline
line
=
mime_decode
(
line
)
message
.
append
(
line
)
if
not
has_iso_chars
:
if
iso_char
.
search
(
line
):
has_iso_chars
=
must_quote_body
=
1
if
not
must_quote_body
:
if
len
(
line
)
>
MAXLEN
:
must_quote_body
=
1
# convert and output header and body
for
line
in
header
:
if
must_quote_header
:
line
=
mime_encode_header
(
line
)
chrset_res
=
chrset
.
match
(
line
)
if
chrset_res
:
if
has_iso_chars
:
# change us-ascii into iso-8859-1
if
string
.
lower
(
chrset_res
.
group
(
2
))
==
'us-ascii'
:
line
=
'%s%s%s'
%
(
chrset_res
.
group
(
1
),
CHARSET
,
chrset_res
.
group
(
3
))
else
:
# change iso-8859-* into us-ascii
line
=
'%sus-ascii%s'
%
chrset_res
.
group
(
1
,
3
)
if
has_cte
and
cte
.
match
(
line
):
line
=
'Content-Transfer-Encoding: '
if
is_base64
:
line
=
line
+
'base64
\
n
'
elif
must_quote_body
:
line
=
line
+
'quoted-printable
\
n
'
else
:
line
=
line
+
'7bit
\
n
'
ofile
.
write
(
line
)
if
(
must_quote_header
or
must_quote_body
)
and
not
is_mime
:
ofile
.
write
(
'Mime-Version: 1.0
\
n
'
)
ofile
.
write
(
'Content-Type: text/plain; '
)
if
has_iso_chars
:
ofile
.
write
(
'charset="%s"
\
n
'
%
CHARSET
)
else
:
ofile
.
write
(
'charset="us-ascii"
\
n
'
)
if
must_quote_body
and
not
has_cte
:
ofile
.
write
(
'Content-Transfer-Encoding: quoted-printable
\
n
'
)
ofile
.
write
(
header_end
)
for
line
in
message
:
if
must_quote_body
:
line
=
mime_encode
(
line
,
0
)
ofile
.
write
(
line
)
ofile
.
write
(
message_end
)
line
=
message_end
while
multipart
:
if
line
==
multipart
+
'--
\
n
'
:
# read bit after the end of the last part
while
1
:
line
=
ifile
.
readline
()
if
not
line
:
return
if
must_quote_body
:
line
=
mime_encode
(
line
,
0
)
ofile
.
write
(
line
)
if
line
==
multipart
+
'
\
n
'
:
nifile
=
File
(
ifile
,
multipart
)
mimify_part
(
nifile
,
ofile
,
1
)
line
=
nifile
.
peek
if
not
line
:
# premature end of file
break
ofile
.
write
(
line
)
continue
# unexpectedly no multipart separator--copy rest of file
while
1
:
line
=
ifile
.
readline
()
if
not
line
:
return
if
must_quote_body
:
line
=
mime_encode
(
line
,
0
)
ofile
.
write
(
line
)
"""Convert an 8bit part of a MIME mail message to quoted-printable."""
has_cte
=
is_qp
=
is_base64
=
0
multipart
=
None
must_quote_body
=
must_quote_header
=
has_iso_chars
=
0
header
=
[]
header_end
=
''
message
=
[]
message_end
=
''
# read header
hfile
=
HeaderFile
(
ifile
)
while
1
:
line
=
hfile
.
readline
()
if
not
line
:
break
if
not
must_quote_header
and
iso_char
.
search
(
line
):
must_quote_header
=
1
if
mv
.
match
(
line
):
is_mime
=
1
if
cte
.
match
(
line
):
has_cte
=
1
if
qp
.
match
(
line
):
is_qp
=
1
elif
base64_re
.
match
(
line
):
is_base64
=
1
mp_res
=
mp
.
match
(
line
)
if
mp_res
:
multipart
=
'--'
+
mp_res
.
group
(
1
)
if
he
.
match
(
line
):
header_end
=
line
break
header
.
append
(
line
)
# read body
while
1
:
line
=
ifile
.
readline
()
if
not
line
:
break
if
multipart
:
if
line
==
multipart
+
'--
\
n
'
:
message_end
=
line
break
if
line
==
multipart
+
'
\
n
'
:
message_end
=
line
break
if
is_base64
:
message
.
append
(
line
)
continue
if
is_qp
:
while
line
[
-
2
:]
==
'=
\
n
'
:
line
=
line
[:
-
2
]
newline
=
ifile
.
readline
()
if
newline
[:
len
(
QUOTE
)]
==
QUOTE
:
newline
=
newline
[
len
(
QUOTE
):]
line
=
line
+
newline
line
=
mime_decode
(
line
)
message
.
append
(
line
)
if
not
has_iso_chars
:
if
iso_char
.
search
(
line
):
has_iso_chars
=
must_quote_body
=
1
if
not
must_quote_body
:
if
len
(
line
)
>
MAXLEN
:
must_quote_body
=
1
# convert and output header and body
for
line
in
header
:
if
must_quote_header
:
line
=
mime_encode_header
(
line
)
chrset_res
=
chrset
.
match
(
line
)
if
chrset_res
:
if
has_iso_chars
:
# change us-ascii into iso-8859-1
if
string
.
lower
(
chrset_res
.
group
(
2
))
==
'us-ascii'
:
line
=
'%s%s%s'
%
(
chrset_res
.
group
(
1
),
CHARSET
,
chrset_res
.
group
(
3
))
else
:
# change iso-8859-* into us-ascii
line
=
'%sus-ascii%s'
%
chrset_res
.
group
(
1
,
3
)
if
has_cte
and
cte
.
match
(
line
):
line
=
'Content-Transfer-Encoding: '
if
is_base64
:
line
=
line
+
'base64
\
n
'
elif
must_quote_body
:
line
=
line
+
'quoted-printable
\
n
'
else
:
line
=
line
+
'7bit
\
n
'
ofile
.
write
(
line
)
if
(
must_quote_header
or
must_quote_body
)
and
not
is_mime
:
ofile
.
write
(
'Mime-Version: 1.0
\
n
'
)
ofile
.
write
(
'Content-Type: text/plain; '
)
if
has_iso_chars
:
ofile
.
write
(
'charset="%s"
\
n
'
%
CHARSET
)
else
:
ofile
.
write
(
'charset="us-ascii"
\
n
'
)
if
must_quote_body
and
not
has_cte
:
ofile
.
write
(
'Content-Transfer-Encoding: quoted-printable
\
n
'
)
ofile
.
write
(
header_end
)
for
line
in
message
:
if
must_quote_body
:
line
=
mime_encode
(
line
,
0
)
ofile
.
write
(
line
)
ofile
.
write
(
message_end
)
line
=
message_end
while
multipart
:
if
line
==
multipart
+
'--
\
n
'
:
# read bit after the end of the last part
while
1
:
line
=
ifile
.
readline
()
if
not
line
:
return
if
must_quote_body
:
line
=
mime_encode
(
line
,
0
)
ofile
.
write
(
line
)
if
line
==
multipart
+
'
\
n
'
:
nifile
=
File
(
ifile
,
multipart
)
mimify_part
(
nifile
,
ofile
,
1
)
line
=
nifile
.
peek
if
not
line
:
# premature end of file
break
ofile
.
write
(
line
)
continue
# unexpectedly no multipart separator--copy rest of file
while
1
:
line
=
ifile
.
readline
()
if
not
line
:
return
if
must_quote_body
:
line
=
mime_encode
(
line
,
0
)
ofile
.
write
(
line
)
def
mimify
(
infile
,
outfile
):
"""Convert 8bit parts of a MIME mail message to quoted-printable."""
if
type
(
infile
)
==
type
(
''
):
ifile
=
open
(
infile
)
if
type
(
outfile
)
==
type
(
''
)
and
infile
==
outfile
:
import
os
d
,
f
=
os
.
path
.
split
(
infile
)
os
.
rename
(
infile
,
os
.
path
.
join
(
d
,
','
+
f
))
else
:
ifile
=
infile
if
type
(
outfile
)
==
type
(
''
):
ofile
=
open
(
outfile
,
'w'
)
else
:
ofile
=
outfile
nifile
=
File
(
ifile
,
None
)
mimify_part
(
nifile
,
ofile
,
0
)
ofile
.
flush
()
"""Convert 8bit parts of a MIME mail message to quoted-printable."""
if
type
(
infile
)
==
type
(
''
):
ifile
=
open
(
infile
)
if
type
(
outfile
)
==
type
(
''
)
and
infile
==
outfile
:
import
os
d
,
f
=
os
.
path
.
split
(
infile
)
os
.
rename
(
infile
,
os
.
path
.
join
(
d
,
','
+
f
))
else
:
ifile
=
infile
if
type
(
outfile
)
==
type
(
''
):
ofile
=
open
(
outfile
,
'w'
)
else
:
ofile
=
outfile
nifile
=
File
(
ifile
,
None
)
mimify_part
(
nifile
,
ofile
,
0
)
ofile
.
flush
()
import
sys
if
__name__
==
'__main__'
or
(
len
(
sys
.
argv
)
>
0
and
sys
.
argv
[
0
]
==
'mimify'
):
import
getopt
usage
=
'Usage: mimify [-l len] -[ed] [infile [outfile]]'
decode_base64
=
0
opts
,
args
=
getopt
.
getopt
(
sys
.
argv
[
1
:],
'l:edb'
)
if
len
(
args
)
not
in
(
0
,
1
,
2
):
print
usage
sys
.
exit
(
1
)
if
((
'-e'
,
''
)
in
opts
)
==
((
'-d'
,
''
)
in
opts
)
or
\
(((
'-b'
,
''
)
in
opts
)
and
((
'-d'
,
''
)
not
in
opts
)):
print
usage
sys
.
exit
(
1
)
for
o
,
a
in
opts
:
if
o
==
'-e'
:
encode
=
mimify
elif
o
==
'-d'
:
encode
=
unmimify
elif
o
==
'-l'
:
try
:
MAXLEN
=
string
.
atoi
(
a
)
except
:
print
usage
sys
.
exit
(
1
)
elif
o
==
'-b'
:
decode_base64
=
1
if
len
(
args
)
==
0
:
encode_args
=
(
sys
.
stdin
,
sys
.
stdout
)
elif
len
(
args
)
==
1
:
encode_args
=
(
args
[
0
],
sys
.
stdout
)
else
:
encode_args
=
(
args
[
0
],
args
[
1
])
if
decode_base64
:
encode_args
=
encode_args
+
(
decode_base64
,)
apply
(
encode
,
encode_args
)
import
getopt
usage
=
'Usage: mimify [-l len] -[ed] [infile [outfile]]'
decode_base64
=
0
opts
,
args
=
getopt
.
getopt
(
sys
.
argv
[
1
:],
'l:edb'
)
if
len
(
args
)
not
in
(
0
,
1
,
2
):
print
usage
sys
.
exit
(
1
)
if
((
'-e'
,
''
)
in
opts
)
==
((
'-d'
,
''
)
in
opts
)
or
\
(((
'-b'
,
''
)
in
opts
)
and
((
'-d'
,
''
)
not
in
opts
)):
print
usage
sys
.
exit
(
1
)
for
o
,
a
in
opts
:
if
o
==
'-e'
:
encode
=
mimify
elif
o
==
'-d'
:
encode
=
unmimify
elif
o
==
'-l'
:
try
:
MAXLEN
=
string
.
atoi
(
a
)
except
:
print
usage
sys
.
exit
(
1
)
elif
o
==
'-b'
:
decode_base64
=
1
if
len
(
args
)
==
0
:
encode_args
=
(
sys
.
stdin
,
sys
.
stdout
)
elif
len
(
args
)
==
1
:
encode_args
=
(
args
[
0
],
sys
.
stdout
)
else
:
encode_args
=
(
args
[
0
],
args
[
1
])
if
decode_base64
:
encode_args
=
encode_args
+
(
decode_base64
,)
apply
(
encode
,
encode_args
)
Lib/multifile.py
View file @
463a4d72
...
...
@@ -13,8 +13,8 @@ fp = MultiFile(real_fp)
"read some lines from fp"
fp.push(separator)
while 1:
"read lines from fp until it returns an empty string" (A)
if not fp.next(): break
"read lines from fp until it returns an empty string" (A)
if not fp.next(): break
fp.pop()
"read remaining lines from fp until it returns an empty string"
...
...
@@ -31,134 +31,134 @@ import sys
import
string
class
Error
(
Exception
):
pass
pass
class
MultiFile
:
seekable
=
0
def
__init__
(
self
,
fp
,
seekable
=
1
):
self
.
fp
=
fp
self
.
stack
=
[]
# Grows down
self
.
level
=
0
self
.
last
=
0
if
seekable
:
self
.
seekable
=
1
self
.
start
=
self
.
fp
.
tell
()
self
.
posstack
=
[]
# Grows down
def
tell
(
self
):
if
self
.
level
>
0
:
return
self
.
lastpos
return
self
.
fp
.
tell
()
-
self
.
start
def
seek
(
self
,
pos
,
whence
=
0
):
here
=
self
.
tell
()
if
whence
:
if
whence
==
1
:
pos
=
pos
+
here
elif
whence
==
2
:
if
self
.
level
>
0
:
pos
=
pos
+
self
.
lastpos
else
:
raise
Error
,
"can't use whence=2 yet"
if
not
0
<=
pos
<=
here
or
\
self
.
level
>
0
and
pos
>
self
.
lastpos
:
raise
Error
,
'bad MultiFile.seek() call'
self
.
fp
.
seek
(
pos
+
self
.
start
)
self
.
level
=
0
self
.
last
=
0
def
readline
(
self
):
if
self
.
level
>
0
:
return
''
line
=
self
.
fp
.
readline
()
# Real EOF?
if
not
line
:
self
.
level
=
len
(
self
.
stack
)
self
.
last
=
(
self
.
level
>
0
)
if
self
.
last
:
raise
Error
,
'sudden EOF in MultiFile.readline()'
return
''
assert
self
.
level
==
0
# Fast check to see if this is just data
if
self
.
is_data
(
line
):
return
line
else
:
# Ignore trailing whitespace on marker lines
k
=
len
(
line
)
-
1
while
line
[
k
]
in
string
.
whitespace
:
k
=
k
-
1
marker
=
line
[:
k
+
1
]
# No? OK, try to match a boundary.
# Return the line (unstripped) if we don't.
for
i
in
range
(
len
(
self
.
stack
)):
sep
=
self
.
stack
[
i
]
if
marker
==
self
.
section_divider
(
sep
):
self
.
last
=
0
break
elif
marker
==
self
.
end_marker
(
sep
):
self
.
last
=
1
break
else
:
return
line
# We only get here if we see a section divider or EOM line
if
self
.
seekable
:
self
.
lastpos
=
self
.
tell
()
-
len
(
line
)
self
.
level
=
i
+
1
if
self
.
level
>
1
:
raise
Error
,
'Missing endmarker in MultiFile.readline()'
return
''
def
readlines
(
self
):
list
=
[]
while
1
:
line
=
self
.
readline
()
if
not
line
:
break
list
.
append
(
line
)
return
list
def
read
(
self
):
# Note: no size argument -- read until EOF only!
return
string
.
joinfields
(
self
.
readlines
(),
''
)
def
next
(
self
):
while
self
.
readline
():
pass
if
self
.
level
>
1
or
self
.
last
:
return
0
self
.
level
=
0
self
.
last
=
0
if
self
.
seekable
:
self
.
start
=
self
.
fp
.
tell
()
return
1
def
push
(
self
,
sep
):
if
self
.
level
>
0
:
raise
Error
,
'bad MultiFile.push() call'
self
.
stack
.
insert
(
0
,
sep
)
if
self
.
seekable
:
self
.
posstack
.
insert
(
0
,
self
.
start
)
self
.
start
=
self
.
fp
.
tell
()
def
pop
(
self
):
if
self
.
stack
==
[]:
raise
Error
,
'bad MultiFile.pop() call'
if
self
.
level
<=
1
:
self
.
last
=
0
else
:
abslastpos
=
self
.
lastpos
+
self
.
start
self
.
level
=
max
(
0
,
self
.
level
-
1
)
del
self
.
stack
[
0
]
if
self
.
seekable
:
self
.
start
=
self
.
posstack
[
0
]
del
self
.
posstack
[
0
]
if
self
.
level
>
0
:
self
.
lastpos
=
abslastpos
-
self
.
start
def
is_data
(
self
,
line
):
return
line
[:
2
]
!=
'--'
def
section_divider
(
self
,
str
):
return
"--"
+
str
def
end_marker
(
self
,
str
):
return
"--"
+
str
+
"--"
seekable
=
0
def
__init__
(
self
,
fp
,
seekable
=
1
):
self
.
fp
=
fp
self
.
stack
=
[]
# Grows down
self
.
level
=
0
self
.
last
=
0
if
seekable
:
self
.
seekable
=
1
self
.
start
=
self
.
fp
.
tell
()
self
.
posstack
=
[]
# Grows down
def
tell
(
self
):
if
self
.
level
>
0
:
return
self
.
lastpos
return
self
.
fp
.
tell
()
-
self
.
start
def
seek
(
self
,
pos
,
whence
=
0
):
here
=
self
.
tell
()
if
whence
:
if
whence
==
1
:
pos
=
pos
+
here
elif
whence
==
2
:
if
self
.
level
>
0
:
pos
=
pos
+
self
.
lastpos
else
:
raise
Error
,
"can't use whence=2 yet"
if
not
0
<=
pos
<=
here
or
\
self
.
level
>
0
and
pos
>
self
.
lastpos
:
raise
Error
,
'bad MultiFile.seek() call'
self
.
fp
.
seek
(
pos
+
self
.
start
)
self
.
level
=
0
self
.
last
=
0
def
readline
(
self
):
if
self
.
level
>
0
:
return
''
line
=
self
.
fp
.
readline
()
# Real EOF?
if
not
line
:
self
.
level
=
len
(
self
.
stack
)
self
.
last
=
(
self
.
level
>
0
)
if
self
.
last
:
raise
Error
,
'sudden EOF in MultiFile.readline()'
return
''
assert
self
.
level
==
0
# Fast check to see if this is just data
if
self
.
is_data
(
line
):
return
line
else
:
# Ignore trailing whitespace on marker lines
k
=
len
(
line
)
-
1
while
line
[
k
]
in
string
.
whitespace
:
k
=
k
-
1
marker
=
line
[:
k
+
1
]
# No? OK, try to match a boundary.
# Return the line (unstripped) if we don't.
for
i
in
range
(
len
(
self
.
stack
)):
sep
=
self
.
stack
[
i
]
if
marker
==
self
.
section_divider
(
sep
):
self
.
last
=
0
break
elif
marker
==
self
.
end_marker
(
sep
):
self
.
last
=
1
break
else
:
return
line
# We only get here if we see a section divider or EOM line
if
self
.
seekable
:
self
.
lastpos
=
self
.
tell
()
-
len
(
line
)
self
.
level
=
i
+
1
if
self
.
level
>
1
:
raise
Error
,
'Missing endmarker in MultiFile.readline()'
return
''
def
readlines
(
self
):
list
=
[]
while
1
:
line
=
self
.
readline
()
if
not
line
:
break
list
.
append
(
line
)
return
list
def
read
(
self
):
# Note: no size argument -- read until EOF only!
return
string
.
joinfields
(
self
.
readlines
(),
''
)
def
next
(
self
):
while
self
.
readline
():
pass
if
self
.
level
>
1
or
self
.
last
:
return
0
self
.
level
=
0
self
.
last
=
0
if
self
.
seekable
:
self
.
start
=
self
.
fp
.
tell
()
return
1
def
push
(
self
,
sep
):
if
self
.
level
>
0
:
raise
Error
,
'bad MultiFile.push() call'
self
.
stack
.
insert
(
0
,
sep
)
if
self
.
seekable
:
self
.
posstack
.
insert
(
0
,
self
.
start
)
self
.
start
=
self
.
fp
.
tell
()
def
pop
(
self
):
if
self
.
stack
==
[]:
raise
Error
,
'bad MultiFile.pop() call'
if
self
.
level
<=
1
:
self
.
last
=
0
else
:
abslastpos
=
self
.
lastpos
+
self
.
start
self
.
level
=
max
(
0
,
self
.
level
-
1
)
del
self
.
stack
[
0
]
if
self
.
seekable
:
self
.
start
=
self
.
posstack
[
0
]
del
self
.
posstack
[
0
]
if
self
.
level
>
0
:
self
.
lastpos
=
abslastpos
-
self
.
start
def
is_data
(
self
,
line
):
return
line
[:
2
]
!=
'--'
def
section_divider
(
self
,
str
):
return
"--"
+
str
def
end_marker
(
self
,
str
):
return
"--"
+
str
+
"--"
Lib/mutex.py
View file @
463a4d72
...
...
@@ -13,39 +13,39 @@ for lock, where a function is called once the lock is aquired.
"""
class
mutex
:
def
__init__
(
self
):
"""Create a new mutex -- initially unlocked."""
self
.
locked
=
0
self
.
queue
=
[]
def
__init__
(
self
):
"""Create a new mutex -- initially unlocked."""
self
.
locked
=
0
self
.
queue
=
[]
def
test
(
self
):
"""Test the locked bit of the mutex."""
return
self
.
locked
def
test
(
self
):
"""Test the locked bit of the mutex."""
return
self
.
locked
def
testandset
(
self
):
"""Atomic test-and-set -- grab the lock if it is not set,
return true if it succeeded."""
if
not
self
.
locked
:
self
.
locked
=
1
return
1
else
:
return
0
def
testandset
(
self
):
"""Atomic test-and-set -- grab the lock if it is not set,
return true if it succeeded."""
if
not
self
.
locked
:
self
.
locked
=
1
return
1
else
:
return
0
def
lock
(
self
,
function
,
argument
):
"""Lock a mutex, call the function with supplied argument
when it is acquired. If the mutex is already locked, place
function and argument in the queue."""
if
self
.
testandset
():
function
(
argument
)
else
:
self
.
queue
.
append
((
function
,
argument
))
def
lock
(
self
,
function
,
argument
):
"""Lock a mutex, call the function with supplied argument
when it is acquired. If the mutex is already locked, place
function and argument in the queue."""
if
self
.
testandset
():
function
(
argument
)
else
:
self
.
queue
.
append
((
function
,
argument
))
def
unlock
(
self
):
"""Unlock a mutex. If the queue is not empty, call the next
function with its argument."""
if
self
.
queue
:
function
,
argument
=
self
.
queue
[
0
]
del
self
.
queue
[
0
]
function
(
argument
)
else
:
self
.
locked
=
0
def
unlock
(
self
):
"""Unlock a mutex. If the queue is not empty, call the next
function with its argument."""
if
self
.
queue
:
function
,
argument
=
self
.
queue
[
0
]
del
self
.
queue
[
0
]
function
(
argument
)
else
:
self
.
locked
=
0
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