Fix lots of py3isms. Email package is borked in py3, however.

This commit is contained in:
Stuart D. Gathman
2016-09-21 17:24:37 -04:00
parent 70fa47dac6
commit bae79a4f1c
10 changed files with 62 additions and 83 deletions
+3 -3
View File
@@ -48,7 +48,7 @@
from __future__ import print_function
import time
from plock import PLock
from Milter.plock import PLock
class AddrCache(object):
time_format = '%Y%b%d %H:%M:%S %Z'
@@ -132,8 +132,8 @@ class AddrCache(object):
if not ts or ts > too_old:
return res
del self.cache[lsender]
raise KeyError, sender
except KeyError,x:
raise KeyError(sender)
except KeyError as x:
try:
user,host = sender.split('@',1)
return self.__getitem__(host)
+4 -1
View File
@@ -2,7 +2,10 @@ import time
import logging
import urllib
import sqlite3
import thread
try:
import thread
except:
import _thread as thread
from datetime import datetime
log = logging.getLogger('milter.greylist')
+3 -3
View File
@@ -11,7 +11,7 @@ class PLock(object):
self.basename = basename
self.fp = None
def lock(self,lockname=None,mode=0660,strict_perms=False):
def lock(self,lockname=None,mode=0o660,strict_perms=False):
"Start an update transaction. Return FILE to write new version."
self.unlock()
if not lockname:
@@ -21,7 +21,7 @@ class PLock(object):
st = os.stat(self.basename)
mode |= st.st_mode
except OSError: pass
u = os.umask(0002)
u = os.umask(0o2)
try:
fd = os.open(lockname,os.O_WRONLY+os.O_CREAT+os.O_EXCL,mode)
finally:
@@ -46,7 +46,7 @@ class PLock(object):
def commit(self,backname=None):
"Commit update transaction with optional backup file."
if not self.fp:
raise IOError,"File not locked"
raise IOError("File not locked")
self.fp.close()
self.fp = None
if backname:
+1 -1
View File
@@ -85,7 +85,7 @@ def inet_pton(p):
::1.2.3.4.5
"""
if p == '::':
return '\0'*16
return b'\0'*16
s = p
m = RE_IP4.search(s)
try:
+15 -31
View File
@@ -2,7 +2,7 @@
# A test framework for milters
from __future__ import print_function
import rfc822
import mime
try:
from StringIO import StringIO
except:
@@ -62,11 +62,11 @@ class TestBase(object):
self._body.write(chunk)
self._bodyreplaced = True
else:
raise IOError,"replacebody not called from eom()"
raise IOError("replacebody not called from eom()")
def chgfrom(self,sender,params=None):
if not self._body:
raise IOError,"chgfrom not called from eom()"
raise IOError("chgfrom not called from eom()")
self.log('chgfrom: sender=%s' % (sender))
self._envfromchanged = True
self._sender = sender
@@ -83,7 +83,7 @@ class TestBase(object):
# work for a %milter
def chgheader(self,field,idx,value):
if not self._body:
raise IOError,"chgheader not called from eom()"
raise IOError("chgheader not called from eom()")
self.log('chgheader: %s[%d]=%s' % (field,idx,value))
if value == '':
del self._msg[field]
@@ -93,19 +93,19 @@ class TestBase(object):
def addheader(self,field,value,idx=-1):
if not self._body:
raise IOError,"addheader not called from eom()"
raise IOError("addheader not called from eom()")
self.log('addheader: %s=%s' % (field,value))
self._msg[field] = value
self._headerschanged = True
def delrcpt(self,rcpt):
if not self._body:
raise IOError,"delrcpt not called from eom()"
raise IOError("delrcpt not called from eom()")
self._delrcpt.append(rcpt)
def addrcpt(self,rcpt):
if not self._body:
raise IOError,"addrcpt not called from eom()"
raise IOError("addrcpt not called from eom()")
self._addrcpt.append(rcpt)
## Save the reply codes and messages in self._reply.
@@ -143,34 +143,21 @@ class TestBase(object):
self._headerschanged = False
self._reply = None
self._sender = '<%s>'%sender
msg = rfc822.Message(fp)
msg = mime.message_from_file(fp)
rc = self.envfrom(self._sender)
if rc != Milter.CONTINUE: return rc
for rcpt in (rcpt,) + rcpts:
rc = self.envrcpt('<%s>'%rcpt)
if rc != Milter.CONTINUE: return rc
line = None
for h in msg.headers:
if h[:1].isspace():
line = line + h
continue
if not line:
line = h
continue
s = line.split(': ',1)
if len(s) > 1: val = s[1].strip()
else: val = ''
rc = self.header(s[0],val)
if rc != Milter.CONTINUE: return rc
line = h
if line:
s = line.split(': ',1)
rc = self.header(s[0],s[1])
for h,val in msg.items():
rc = self.header(h,val)
if rc != Milter.CONTINUE: return rc
rc = self.eoh()
if rc != Milter.CONTINUE: return rc
header,body = msg.as_bytes().split(b'\n\n',1)
bfp = StringIO(body)
while 1:
buf = fp.read(8192)
buf = bfp.read(8192)
if len(buf) == 0: break
rc = self.body(buf)
if rc != Milter.CONTINUE: return rc
@@ -179,12 +166,9 @@ class TestBase(object):
rc = self.eom()
if self._bodyreplaced:
body = self._body.getvalue()
else:
msg.rewindbody()
body = msg.fp.read()
self._body = StringIO()
self._body.writelines(msg.headers)
self._body.write('\n')
self._body.write(header)
self._body.write('\n\n')
self._body.write(body)
return rc
+10 -12
View File
@@ -5,13 +5,11 @@
import re
import struct
import socket
import email.Errors
import email.errors
from email.header import decode_header
import email.base64mime
from fnmatch import fnmatchcase
from email.Header import decode_header
from binascii import a2b_base64
#import email.Utils
import rfc822
dnsre = re.compile(r'^[a-z][-a-z\d.]+$', re.IGNORECASE)
PAT_IP4 = r'\.'.join([r'(?:\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])']*4)
@@ -56,8 +54,8 @@ if hasattr(socket,'has_ipv6') and socket.has_ipv6:
else:
from pyip6 import inet_ntop, inet_pton
MASK = 0xFFFFFFFFL
MASK6 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL
MASK = 0xFFFFFFFF
MASK6 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
def cidr(i,n,mask=MASK):
return ~(mask >> n) & mask & i
@@ -119,7 +117,7 @@ def iniplist(ipaddr,iplist):
return False
## Split email into Fullname and address.
# This replaces <code>email.Utils.parseaddr</code> but fixes
# This replaces <code>email.utils.parseaddr</code> but fixes
# some <a href="http://bugs.python.org/issue1025395">tricky test cases</a>.
# Additional tricky cases are still broken. Patches welcome.
#
@@ -139,8 +137,8 @@ def parseaddr(t):
>>> parseaddr('a(WRONG)@b')
('WRONG', 'a@b')
"""
#return email.Utils.parseaddr(t)
res = rfc822.parseaddr(t)
#return email.utils.parseaddr(t)
res = email.utils.parseaddr(t)
# dirty fix for some broken cases
if not res[0]:
pos = t.find('<')
@@ -149,7 +147,7 @@ def parseaddr(t):
pos1 = addrspec.rfind(':')
if pos1 > 0:
addrspec = addrspec[pos1+1:]
return rfc822.parseaddr('"%s" <%s>' % (t[:pos].strip(),addrspec))
return email.utils.parseaddr('"%s" <%s>' % (t[:pos].strip(),addrspec))
if not res[1]:
pos = t.find('<')
if pos > 0 and t[-1] == '>':
@@ -157,7 +155,7 @@ def parseaddr(t):
pos1 = addrspec.rfind(':')
if pos1 > 0:
addrspec = addrspec[pos1+1:]
return rfc822.parseaddr('%s<%s>' % (t[:pos].strip(),addrspec))
return email.utils.parseaddr('%s<%s>' % (t[:pos].strip(),addrspec))
return res
## Fix email.base64mime.decode to add any missing padding
@@ -227,5 +225,5 @@ def parse_header(val):
except UnicodeDecodeError: pass
except LookupError: pass
except ValueError: pass
except email.Errors.HeaderParseError: pass
except email.errors.HeaderParseError: pass
return val
+17 -21
View File
@@ -103,15 +103,12 @@ import Milter
import zipfile
import email
import email.Message
from email.Message import Message
from email.Generator import Generator
from email.Utils import quote
from email import Utils
from email.Parser import Parser
from email import Errors
from email.message import Message
from email.generator import Generator
from email.utils import quote
from types import ListType,StringType
if not getattr(Message,'as_bytes',None):
Message.as_bytes = Message.as_string
## Return a list of filenames in a zip file.
# Embedded zip files are recursively expanded.
@@ -154,19 +151,17 @@ def unquote(s):
return s[1:-1]
return s
from types import TupleType
def _unquotevalue(value):
if isinstance(value, TupleType):
if isinstance(value, tuple):
return value[0], value[1], unquote(value[2])
else:
return unquote(value)
#email.Message._unquotevalue = _unquotevalue
from email.Message import _parseparam
from email.message import _parseparam
## Enhance email.Message
## Enhance email.message.Message
#
# Tracks modifications to headers of body or any part independently.
@@ -207,7 +202,7 @@ class MimeMessage(Message):
interpret as a name - and hence decide to execute this message."""
names = []
for attr,val in self._get_params_preserve([],'content-type'):
if isinstance(val, TupleType):
if isinstance(val, tuple):
# It's an RFC 2231 encoded parameter
newvalue = _unquotevalue(val)
if val[0]:
@@ -355,8 +350,6 @@ def check_name(msg,savname=None,ckname=check_ext,scan_zip=False):
msg["Content-Type"] = "text/plain; name="+name
return Milter.CONTINUE
import email.Iterators
def check_attachments(msg,check):
"""Scan attachments.
msg MimeMessage
@@ -402,18 +395,21 @@ class _defang:
# emulate old defang function
defang = _defang()
import sgmllib
try:
from html.parser import HTMLParser
except:
from sgmllib import SGMLParser as HTMLParser
import re
declname = re.compile(r'[a-zA-Z][-_.a-zA-Z0-9]*\s*')
declstringlit = re.compile(r'(\'[^\']*\'|"[^"]*")\s*')
class SGMLFilter(sgmllib.SGMLParser):
class SGMLFilter(HTMLParser):
"""Parse HTML and pass through all constructs unchanged. It is intended for
derived classes to implement exceptional processing for selected cases.
"""
def __init__(self,out):
sgmllib.SGMLParser.__init__(self)
HTMLParser.__init__(self)
self.out = out
def handle_comment(self,comment):
@@ -444,7 +440,7 @@ class SGMLFilter(sgmllib.SGMLParser):
self.out.write("<!%s>" % data)
def write(self,buf):
"Act like a writer. Why doesn't SGMLParser do this by default?"
"Act like a writer. Why doesn't HTMLParser do this by default?"
self.feed(buf)
# Python-2.1 sgmllib rejects illegal declarations. Since various Microsoft
@@ -545,5 +541,5 @@ if __name__ == '__main__':
for fname in sys.argv[1:]:
fp = open(fname)
msg = message_from_file(fp)
email.Iterators._structure(msg)
email.iterators._structure(msg)
check_attachments(msg,_list_attach)
+4 -8
View File
@@ -11,7 +11,6 @@ try:
from StringIO import StringIO
except:
from io import StringIO
import rfc822
import mime
import Milter
import tempfile
@@ -141,19 +140,16 @@ class sampleMilter(Milter.Milter):
self.log("Temp file:",self.tempname)
self.tempname = None # prevent removal of original message copy
# copy defanged message to a temp file
out = tempfile.TemporaryFile()
try:
with tempfile.TemporaryFile() as out:
msg.dump(out)
out.seek(0)
msg = rfc822.Message(out)
msg.rewindbody()
msg = mime.message_from_file(out)
fp = StringIO(msg.as_bytes().split(b'\n\n',1)[1])
while 1:
buf = out.read(8192)
buf = fp.read(8192)
if len(buf) == 0: break
self.replacebody(buf) # feed modified message to sendmail
return Milter.ACCEPT # ACCEPT modified message
finally:
out.close()
return Milter.TEMPFAIL
def close(self):
+5 -2
View File
@@ -37,7 +37,10 @@ except:
import email
import sys
import Milter
from email import Errors
try:
from email import Errors as errors
except:
from email import errors
samp1_txt1 = """Dear Agent 1
I hope you can read this. Whenever you write label it P.B.S kids.
@@ -77,7 +80,7 @@ class MimeTestCase(unittest.TestCase):
# if message is modified, output is readable by mail clients
if sys.hexversion < 0x02040000:
self.fail('should get boundary error parsing bad rfc822 attachment')
except Errors.BoundaryError:
except errors.BoundaryError:
pass
def testDefang(self,vname='virus1',part=1,
-1
View File
@@ -2,7 +2,6 @@ import unittest
import Milter
import sample
import mime
import rfc822
from Milter.test import TestBase
class TestMilter(TestBase,sample.sampleMilter):