diff --git a/pyquarantine/__init__.py b/pyquarantine/__init__.py
index e2bc75c..9709590 100644
--- a/pyquarantine/__init__.py
+++ b/pyquarantine/__init__.py
@@ -14,22 +14,21 @@
__all__ = ["QuarantineMilter", "generate_milter_config", "reload_config", "mailer", "notifications", "run", "quarantines", "whitelists"]
-import ConfigParser
import Milter
-import StringIO
+import configparser
import logging
import os
import re
import sys
-import mailer
-import quarantines
-import notifications
-import whitelists
-
from Milter.utils import parse_addr
+from io import BytesIO
from itertools import groupby
+from pyquarantine import quarantines
+from pyquarantine import notifications
+from pyquarantine import whitelists
+
class QuarantineMilter(Milter.Base):
"""QuarantineMilter based on Milter.Base to implement milter communication
@@ -171,9 +170,9 @@ class QuarantineMilter(Milter.Base):
if keep_body:
self.logger.debug("{}: initializing memory buffer to save email data".format(self.queueid))
# initialize memory buffer to save email data
- self.fp = StringIO.StringIO()
+ self.fp = BytesIO()
# write email headers to memory buffer
- self.fp.write("{}\n".format("\n".join(self.headers)))
+ self.fp.write("{}\n".format("\n".join(self.headers)).encode())
else:
# quarantine and notification are disabled on all matching quarantines, return configured action
quarantine = self._get_preferred_quarantine()
@@ -256,7 +255,7 @@ def generate_milter_config(configtest=False, config_files=[]):
logger = logging.getLogger(__name__)
# read config file
- parser = ConfigParser.ConfigParser()
+ parser = configparser.ConfigParser()
if not config_files:
config_files = parser.read(QuarantineMilter.get_configfiles())
else:
diff --git a/pyquarantine/cli.py b/pyquarantine/cli.py
index 4f7ae99..39409ac 100644
--- a/pyquarantine/cli.py
+++ b/pyquarantine/cli.py
@@ -201,7 +201,10 @@ def release_email(config, args):
raise RuntimeError("quarantine type is set to None, unable to release e-mail")
quarantine.release(args.quarantine_id, args.recipient)
- logger.info("successfully released e-mail [quarantine-id: {}] to '{}' from quarantine '{}'".format(args.quarantine_id, args.recipient, args.quarantine))
+ if args.recipient:
+ logger.info("successfully released quarantined email '{}' to '{}' from quarantine '{}'".format(args.quarantine_id, args.recipient, args.quarantine))
+ else:
+ logger.info("successfully released quarantined email '{}' from quarantine '{}'".format(args.quarantine_id, args.quarantine))
def delete_email(config, args):
diff --git a/pyquarantine/mailer.py b/pyquarantine/mailer.py
index e9a0c27..76e5117 100644
--- a/pyquarantine/mailer.py
+++ b/pyquarantine/mailer.py
@@ -15,6 +15,7 @@
import logging
import smtplib
import sys
+
from multiprocessing import Process, Queue
diff --git a/pyquarantine/notifications.py b/pyquarantine/notifications.py
index 242ecc4..89058c4 100644
--- a/pyquarantine/notifications.py
+++ b/pyquarantine/notifications.py
@@ -14,7 +14,6 @@
import email
import logging
-import mailer
import re
from bs4 import BeautifulSoup
@@ -23,6 +22,7 @@ from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
+from pyquarantine import mailer
class BaseNotification(object):
"Notification base class"
@@ -118,7 +118,7 @@ class EMailNotification(BaseNotification):
# read email notification template
try:
- self.template = open(self.config["notification_email_template"], "rb").read()
+ self.template = open(self.config["notification_email_template"], "r").read()
except IOError as e:
raise RuntimeError("error reading template: {}".format(e))
@@ -139,7 +139,7 @@ class EMailNotification(BaseNotification):
if mimetype == EMailNotification._plain_text:
self.logger.debug("{}: content mimetype is {}, converting to {}".format(queueid, mimetype, self._html_text))
- text = re.sub(r"^(.*)$", r"\1
\n", text, flags=re.MULTILINE)
+ text = re.sub(r"^(.*)$", r"\1
\n", text.decode(), flags=re.MULTILINE)
else:
self.logger.debug("{}: content mimetype is {}".format(queueid, mimetype))
@@ -211,7 +211,7 @@ class EMailNotification(BaseNotification):
# extract html text from email
self.logger.debug("{}: extraction email text from original email".format(queueid))
- soup = self.get_html_text_part(queueid, email.message_from_file(fp))
+ soup = self.get_html_text_part(queueid, email.message_from_binary_file(fp))
# replace picture sources
picture_replaced = False
diff --git a/pyquarantine/quarantines.py b/pyquarantine/quarantines.py
index a8ef1be..5129bf2 100644
--- a/pyquarantine/quarantines.py
+++ b/pyquarantine/quarantines.py
@@ -22,7 +22,7 @@ from glob import glob
from shutil import copyfileobj
from time import gmtime
-import mailer
+from pyquarantine import mailer
class BaseQuarantine(object):
@@ -84,7 +84,7 @@ class FileQuarantine(BaseQuarantine):
def _save_metafile(self, quarantine_id, metadata):
metafile = os.path.join(self.directory, "{}{}".format(quarantine_id, self._metadata_suffix))
try:
- with open(metafile, "wb") as f:
+ with open(metafile, "w") as f:
json.dump(metadata, f, indent=2)
except IOError as e:
raise RuntimeError("unable to save metadata file: {}".format(e))
@@ -136,10 +136,12 @@ class FileQuarantine(BaseQuarantine):
raise RuntimeError("invalid quarantine id '{}'".format(quarantine_id))
try:
- with open(metafile, "rb") as f:
+ with open(metafile, "r") as f:
metadata = json.load(f)
except IOError as e:
raise RuntimeError("unable to read metadata file: {}".format(e))
+ except json.JSONDecodeError as e:
+ raise RuntimeError("invalid meta file '{}': {}".format(metafile, e))
return metadata
diff --git a/pyquarantine/whitelists.py b/pyquarantine/whitelists.py
index f22ef19..c7103a7 100644
--- a/pyquarantine/whitelists.py
+++ b/pyquarantine/whitelists.py
@@ -17,6 +17,7 @@ import logging
import peewee
import re
import sys
+
from playhouse.db_url import connect