"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/fuglu/mshared.py" between
fuglu-0.10.8.tar.gz and fuglu-1.0.0.tar.gz

About: FuGlu is a mail scanning daemon for Postfix written in Python. It acts as a glue application between the MTA and spam checkers and antivirus software.

mshared.py  (fuglu-0.10.8):mshared.py  (fuglu-1.0.0)
import logging import logging
import time import time
import asyncio
import functools
try: try:
#from contextlib import AbstractAsyncContextManager #from contextlib import AbstractAsyncContextManager
from contextlib import AbstractContextManager from contextlib import AbstractContextManager
except ImportError: except ImportError:
#AbstractAsyncContextManager = object #AbstractAsyncContextManager = object
AbstractContextManager = object AbstractContextManager = object
import typing as tp import typing as tp
from typing import Dict, Tuple, Union from typing import Dict, Tuple, Union
from types import TracebackType from types import TracebackType
import fuglu.connectors.milterconnector as sm import fuglu.connectors.milterconnector as sm
import fuglu.connectors.asyncmilterconnector as asm import fuglu.connectors.asyncmilterconnector as asm
from fuglu.scansession import TrackTimings from fuglu.scansession import TrackTimings
from fuglu.mixins import ReturnOverrideMixin
from fuglu.connectors.milterconnector import ( from fuglu.connectors.milterconnector import (
CONNECT, CONNECT,
HELO, HELO,
MAILFROM, MAILFROM,
RCPT, RCPT,
HEADER, HEADER,
EOH, EOH,
EOB, EOB,
ACCEPT, ACCEPT,
CONTINUE, CONTINUE,
DISCARD, DISCARD,
TEMPFAIL, TEMPFAIL,
REJECT, REJECT,
) )
import fuglu.shared as fs import fuglu.shared as fs
EOM = "eom" # end-of-message state for non-milter-call
# conversion return code to Milter return code # conversion return code to Milter return code
retcode2milter = { retcode2milter = {
fs.DUNNO: CONTINUE, fs.DUNNO: CONTINUE,
fs.ACCEPT: ACCEPT, fs.ACCEPT: ACCEPT,
fs.DELETE: DISCARD, fs.DELETE: DISCARD,
fs.REJECT: REJECT, fs.REJECT: REJECT,
fs.DEFER: TEMPFAIL, fs.DEFER: TEMPFAIL,
} }
def convert_return2milter(ret: tp.Union[int, tp.Tuple[int, str]]) \
-> tp.Union[bytes, tp.Tuple[bytes, str]]:
"""Convert return code (simple or tuple with message string) to milter retur
n code"""
if isinstance(ret, tuple):
return retcode2milter[ret[0]], ret[1]
elif isinstance(ret, int):
return retcode2milter[ret]
else:
raise ValueError(f"ret type should be tuple(int, str) or int -> but is {
type(ret)}")
class SumAsyncTime(AbstractContextManager): class SumAsyncTime(AbstractContextManager):
"""Async context manager to additionally sum async await calls""" """Async context manager to additionally sum async await calls"""
def __init__(self, timer: TrackTimings, key: tp.Optional[str] = None, logid: tp.Optional[str] = None): def __init__(self, timer: TrackTimings, key: tp.Optional[str] = None, logid: tp.Optional[str] = None):
self.timer = timer self.timer = timer
self.asyncstart = None self.asyncstart = None
self.asyncend = None self.asyncend = None
self.key = key self.key = key
self.logid = logid self.logid = logid
self.logger = logging.getLogger('fuglu.SumAsyncTime') self.logger = logging.getLogger('fuglu.SumAsyncTime')
def __enter__(self): def __enter__(self):
self.asyncstart = time.time() self.asyncstart = time.time()
#self.logger.debug(f"{self.logid} ({self.key}) -> enter with time {self. asyncstart}") #self.logger.debug(f"{self.logid} ({self.key}) -> enter with time {self. asyncstart}")
def __exit__(self, exc_type: tp.Optional[tp.Type[BaseException]], exc_value: tp.Optional[BaseException], traceback: tp.Optional[TracebackType]): def __exit__(self, exc_type: tp.Optional[tp.Type[BaseException]], exc_value: tp.Optional[BaseException], traceback: tp.Optional[TracebackType]):
self.asyncend = time.time() self.asyncend = time.time()
#self.logger.debug(f"{self.logid} ({self.key}) -> exit with time {self.a syncend}") #self.logger.debug(f"{self.logid} ({self.key}) -> exit with time {self.a syncend}")
self.timer.sum_asynctime(self.asyncend - self.asyncstart, self.key, logi d=self.logid) self.timer.sum_asynctime(self.asyncend - self.asyncstart, self.key, logi d=self.logid)
class MilterSuspect:
"""Milter Suspect"""
def __init__(self, id: str, values: Dict[str, str]):
self.logger = logging.getLogger("Fuglu.MSuspect")
# logger
self.id = id
self.values = values
#all values offered by postfix (dict)
class BMPConnectMixin: class BMPConnectMixin:
"""Basic Milter Plugin Mixing to implement plugin for connect state""" """Basic Milter Plugin Mixing to implement plugin for connect state which ca n be a coroutine"""
def examine_connect(self, sess: Union[sm.MilterSession, asm.MilterSession], host: str, addr: str) -> Union[bytes, Tuple[bytes, str]]: def examine_connect(self, sess: Union[sm.MilterSession, asm.MilterSession], host: str, addr: str) -> Union[bytes, Tuple[bytes, str]]:
"""Examine connect state, return action code or tuple with action code a nd message""" """(async) Examine connect state, return action code or tuple with actio n code and message"""
raise NotImplementedError() raise NotImplementedError()
class BMPHeloMixin: class BMPHeloMixin:
"""Basic Milter Plugin Mixing to implement plugin for helo state""" """Basic Milter Plugin Mixing to implement plugin for helo state which can b e a coroutine"""
def examine_helo(self, sess: Union[sm.MilterSession, asm.MilterSession], hel o: str) -> Union[bytes, Tuple[bytes, str]]: def examine_helo(self, sess: Union[sm.MilterSession, asm.MilterSession], hel o: str) -> Union[bytes, Tuple[bytes, str]]:
"""Examine helo state, return action code or tuple with action code and message""" """(async) Examine helo state, return action code or tuple with action c ode and message"""
raise NotImplementedError() raise NotImplementedError()
class BMPMailFromMixin: class BMPMailFromMixin:
"""Basic Milter Plugin Mixing to implement plugin for mailfrom state""" """Basic Milter Plugin Mixing to implement plugin for mailfrom state which c an be a coroutine"""
def examine_mailfrom(self, sess: Union[sm.MilterSession, asm.MilterSession], sender: str) -> Union[bytes, Tuple[bytes, str]]: def examine_mailfrom(self, sess: Union[sm.MilterSession, asm.MilterSession], sender: str) -> Union[bytes, Tuple[bytes, str]]:
"""Examine mailfrom state, return action code or tuple with action code and message""" """(async) Examine mailfrom state, return action code or tuple with acti on code and message"""
raise NotImplementedError() raise NotImplementedError()
class BMPRCPTMixin: class BMPRCPTMixin:
"""Basic Milter Plugin Mixing to implement plugin for rcpt state""" """Basic Milter Plugin Mixing to implement plugin for rcpt state which can b e a coroutine"""
def examine_rcpt(self, sess: Union[sm.MilterSession, asm.MilterSession], rec ipient: str) -> Union[bytes, Tuple[bytes, str]]: def examine_rcpt(self, sess: Union[sm.MilterSession, asm.MilterSession], rec ipient: str) -> Union[bytes, Tuple[bytes, str]]:
"""Examine recipient state, return action code or tuple with action code and message""" """(async) Examine recipient state, return action code or tuple with act ion code and message"""
raise NotImplementedError() raise NotImplementedError()
class BMPHeaderMixin: class BMPHeaderMixin:
"""Basic Milter Plugin Mixing to implement plugin for header state""" """Basic Milter Plugin Mixing to implement plugin for header state which can be a coroutine"""
def examine_header(self, sess: Union[sm.MilterSession, asm.MilterSession], k ey: bytes, value: bytes) -> Union[bytes, Tuple[bytes, str]]: def examine_header(self, sess: Union[sm.MilterSession, asm.MilterSession], k ey: bytes, value: bytes) -> Union[bytes, Tuple[bytes, str]]:
"""Examine header state, return action code or tuple with action code an d message""" """(async) Examine header state, return action code or tuple with action code and message"""
raise NotImplementedError() raise NotImplementedError()
class BMPEOHMixin: class BMPEOHMixin:
"""Basic Milter Plugin Mixing to implement plugin for end-of-headers state"" " """Basic Milter Plugin Mixing to implement plugin for end-of-headers state w hich can be a coroutine"""
def examine_eoh(self, sess: Union[sm.MilterSession, asm.MilterSession]) -> U nion[bytes, Tuple[bytes, str]]: def examine_eoh(self, sess: Union[sm.MilterSession, asm.MilterSession]) -> U nion[bytes, Tuple[bytes, str]]:
"""Examine eoh state, return action code or tuple with action code and m essage""" """(async) Examine eoh state, return action code or tuple with action co de and message"""
raise NotImplementedError() raise NotImplementedError()
class BMPEOBMixin: class BMPEOBMixin(ReturnOverrideMixin):
"""Basic Milter Plugin Mixing to implement plugin for end-of-body state""" """Basic Milter Plugin Mixing to implement plugin for end-of-body state whic
h can be a coroutine"""
def examine_eob(self, sess: Union[sm.MilterSession, asm.MilterSession]) -> U nion[bytes, Tuple[bytes, str]]: def examine_eob(self, sess: Union[sm.MilterSession, asm.MilterSession]) -> U nion[bytes, Tuple[bytes, str]]:
"""Examine eob state, return action code or tuple with action code and m essage""" """(async) Examine eob state, return action code or tuple with action co de and message"""
raise NotImplementedError() raise NotImplementedError()
class BasicMilterPlugin(fs.BasicPlugin): class BasicMilterPlugin(ReturnOverrideMixin, fs.BasicPlugin):
"""Base for milter plugins, derive from BMP***Mixins above to implement stat es""" """Base for milter plugins, derive from BMP***Mixins above to implement stat es"""
ALL_STATES = { ALL_STATES = {
CONNECT: BMPConnectMixin, CONNECT: BMPConnectMixin,
HELO: BMPHeloMixin, HELO: BMPHeloMixin,
MAILFROM: BMPMailFromMixin, MAILFROM: BMPMailFromMixin,
RCPT: BMPRCPTMixin, RCPT: BMPRCPTMixin,
HEADER: BMPHeaderMixin, HEADER: BMPHeaderMixin,
EOH: BMPEOHMixin, EOH: BMPEOHMixin,
EOB: BMPEOBMixin, EOB: BMPEOBMixin,
skipping to change at line 140 skipping to change at line 145
'default': '', 'default': '',
'description': f'comma/space separated list states this plugin s hould be ' 'description': f'comma/space separated list states this plugin s hould be '
f'applied ({",".join(BasicMilterPlugin.ALL_STATES .keys())})' f'applied ({",".join(BasicMilterPlugin.ALL_STATES .keys())})'
} }
}) })
self._state = None self._state = None
self.logger = self._logger() self.logger = self._logger()
@property @property
def state(self): def state(self):
"""states list this plugin is active in"""
if self._state is None: if self._state is None:
self._state = [s.lower() for s in fs.Suspect.getlist_space_comma_sep arated(self.config.get(self.section, 'state'))] self._state = [s.lower() for s in fs.Suspect.getlist_space_comma_sep arated(self.config.get(self.section, 'state'))]
return self._state return self._state
def lint(self, **kwargs) -> bool: def lint(self, **kwargs) -> bool:
"""Basic lint, check if given state exists & implementation of state"""
if not super().lint(): if not super().lint():
return False return False
checkstates = kwargs.get('state', self.state) checkstates = kwargs.get('state', self.state)
if isinstance(checkstates, str): if isinstance(checkstates, str):
checkstates = [checkstates] checkstates = [checkstates]
if not all(s in BasicMilterPlugin.ALL_STATES.keys() for s in checkstates ): if not all(s in BasicMilterPlugin.ALL_STATES.keys() for s in checkstates ):
print("Error: Not all states are available/implemented") print("Error: Not all states are available/implemented")
print(f"checkstates: {checkstates}") print(f"checkstates: {checkstates}")
 End of changes. 22 change blocks. 
26 lines changed or deleted 36 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)