diff --git a/imap_filter/imap_filter.py b/imap_filter/imap_filter.py index 78aeff4..c100ed5 100644 --- a/imap_filter/imap_filter.py +++ b/imap_filter/imap_filter.py @@ -13,14 +13,14 @@ import imaplib import email from signal import signal, SIGINT import json -from yaml import load, dump -try: - from yaml import CLoader as Loader, CDumper as Dumper -except ImportError: - from yaml import Loader, Dumper import re import codecs import time +from yaml import load +try: + from yaml import CLoader as Loader +except ImportError: + from yaml import Loader import click import click_config_file @@ -64,6 +64,8 @@ class ImapFilter: def _process_filters(self): matches = 0 for mailbox in self.config['mailboxes']: + if mailbox['mailbox'] == 'INBOX' and self.config['sieve_scripts_path']: + self._create_sieve_script(mailbox['filters']) self._log.debug( "Processing mailbox '%s'...", mailbox['mailbox'] @@ -132,6 +134,32 @@ class ImapFilter: ) return True + def _create_sieve_script(self, filters): + if os.path.exists(self.config['sieve_scripts_path']): + with open(self.config['sieve_scripts_path'], 'r', encoding='UTF-8') as sieve_script: + content = sieve_script.read() + else: + content = '# Managed by imap_filter. Some lines might get replaced if the match with rule name from imap_filter' + for mfilter in filters: + if 'field' in mfilter: + field = mfilter['field'] + else: + field = 'From' + if 'regexp' in mfilter: + condition = f'allof (header :contains "{field}" "{mfilter['regexp']}")' + else: + condition = f'allof (header :contains "{field}" ["{'", "'.join(mfilter['words'])}"])' + search = f'^.* # imap_filter: rule name \'imap_filter_INBOX_{mfilter['name']}\'' + replacement = f'if {condition} {{ fileinto "{mfilter['destination']}"; stop;}} # imap_filter: rule name \'imap_filter_INBOX_{mfilter['name']}\'' + new_content = re.sub(search, replacement, content) + if content == new_content: + content += f"{replacement}\n" + else: + content = f"{new_content}\n" + with open(self.config['sieve_scripts_path'], 'w', encoding='UTF-8') as sieve_script: + sieve_script.write(content) + return True + def _process_message(self, message_id, data, mfilter): '''Process a mail message''' if isinstance(data[1], int): @@ -403,6 +431,11 @@ class ImapFilter: '--filters-file', '-F', required=True, help='JSON or YAML file containing a list of dictionaries with the filter rules.' ) +@click.option( + '--sieve-scripts-path', + '-P', + help='Path to create sieve scripts.' +) @click_config_file.configuration_option() def __main__(**kwargs): return ImapFilter(**kwargs) diff --git a/pyproject.toml b/pyproject.toml index 7a33234..ecfe8b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,14 +3,14 @@ requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta" [project.urls] -Homepage = "__url__" +Homepage = "https://repos.susurrando.com/adelgado/imap_filter.git" [project] name = "imap_filter" version = "0.0.1" description = "IMAP filter tool" readme = "README.md" -authors = [{ name = "Antonio J. Delgado", email = "" }] +authors = [{ name = "Antonio J. Delgado", email = "ad@susurrando.com" }] license = { file = "LICENSE" } classifiers = [ "License :: OSI Approved :: GPLv3 License", @@ -22,4 +22,4 @@ dependencies = [ "click", "click_config_file", ] -requires-python = ">=3" \ No newline at end of file +requires-python = ">=3" diff --git a/requirements.txt b/requirements.txt index 66bf966..4656139 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ click -click_config_file \ No newline at end of file +click_config_file +pyyaml diff --git a/setup.py b/setup.py index 841ee92..dcdff7a 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setuptools.setup( author="Antonio J. Delgado", version=config['metadata']['version'], name=config['metadata']['name'], - author_email="", + author_email="ad@susurrando.com", url="__url__", description="IMAP filter tool", long_description="README.md",