Fixes handling of gmail label extension to IMAP

This commit is contained in:
Trenton H 2022-10-07 07:57:26 -07:00
parent 9c0c734b34
commit 55089aab32
2 changed files with 44 additions and 17 deletions

View File

@ -4,6 +4,7 @@ import tempfile
from datetime import date from datetime import date
from datetime import timedelta from datetime import timedelta
from fnmatch import fnmatch from fnmatch import fnmatch
from typing import Dict
import magic import magic
import pathvalidate import pathvalidate
@ -30,7 +31,7 @@ class MailError(Exception):
class BaseMailAction: class BaseMailAction:
def get_criteria(self): def get_criteria(self) -> Dict:
return {} return {}
def post_consume(self, M, message_uids, parameter): def post_consume(self, M, message_uids, parameter):
@ -78,7 +79,7 @@ class TagMailAction(BaseMailAction):
M.flag(message_uids, [self.keyword], True) M.flag(message_uids, [self.keyword], True)
def get_rule_action(rule): def get_rule_action(rule) -> BaseMailAction:
if rule.action == MailRule.MailAction.FLAG: if rule.action == MailRule.MailAction.FLAG:
return FlagMailAction() return FlagMailAction()
elif rule.action == MailRule.MailAction.DELETE: elif rule.action == MailRule.MailAction.DELETE:
@ -108,7 +109,7 @@ def make_criterias(rule):
return {**criterias, **get_rule_action(rule).get_criteria()} return {**criterias, **get_rule_action(rule).get_criteria()}
def get_mailbox(server, port, security): def get_mailbox(server, port, security) -> MailBox:
if security == MailAccount.ImapSecurity.NONE: if security == MailAccount.ImapSecurity.NONE:
mailbox = MailBoxUnencrypted(server, port) mailbox = MailBoxUnencrypted(server, port)
elif security == MailAccount.ImapSecurity.STARTTLS: elif security == MailAccount.ImapSecurity.STARTTLS:
@ -167,7 +168,7 @@ class MailAccountHandler(LoggingMixin):
"Unknown correspondent selector", "Unknown correspondent selector",
) # pragma: nocover ) # pragma: nocover
def handle_mail_account(self, account): def handle_mail_account(self, account: MailAccount):
self.renew_logging_group() self.renew_logging_group()
@ -181,7 +182,14 @@ class MailAccountHandler(LoggingMixin):
account.imap_security, account.imap_security,
) as M: ) as M:
supports_gmail_labels = "X-GM-EXT-1" in M.client.capabilities
supports_auth_plain = "AUTH=PLAIN" in M.client.capabilities
self.log("debug", f"GMAIL Label Support: {supports_gmail_labels}")
self.log("debug", f"AUTH=PLAIN Support: {supports_auth_plain}")
try: try:
M.login(account.username, account.password) M.login(account.username, account.password)
except UnicodeEncodeError: except UnicodeEncodeError:
@ -215,7 +223,11 @@ class MailAccountHandler(LoggingMixin):
for rule in account.rules.order_by("order"): for rule in account.rules.order_by("order"):
try: try:
total_processed_files += self.handle_mail_rule(M, rule) total_processed_files += self.handle_mail_rule(
M,
rule,
supports_gmail_labels,
)
except Exception as e: except Exception as e:
self.log( self.log(
"error", "error",
@ -233,7 +245,12 @@ class MailAccountHandler(LoggingMixin):
return total_processed_files return total_processed_files
def handle_mail_rule(self, M: MailBox, rule): def handle_mail_rule(
self,
M: MailBox,
rule: MailRule,
supports_gmail_labels: bool = False,
):
self.log("debug", f"Rule {rule}: Selecting folder {rule.folder}") self.log("debug", f"Rule {rule}: Selecting folder {rule.folder}")
@ -261,11 +278,19 @@ class MailAccountHandler(LoggingMixin):
) from err ) from err
criterias = make_criterias(rule) criterias = make_criterias(rule)
criterias_imap = AND(**criterias)
# Deal with the Gmail label extension
if "gmail_label" in criterias: if "gmail_label" in criterias:
gmail_label = criterias["gmail_label"] gmail_label = criterias["gmail_label"]
del criterias["gmail_label"] del criterias["gmail_label"]
criterias_imap = AND(NOT(gmail_label=gmail_label), **criterias)
if not supports_gmail_labels:
criterias_imap = AND(**criterias)
else:
criterias_imap = AND(NOT(gmail_label=gmail_label), **criterias)
else:
criterias_imap = AND(**criterias)
self.log( self.log(
"debug", "debug",

View File

@ -47,15 +47,16 @@ class BogusFolderManager:
class BogusClient: class BogusClient:
def __init__(self, messages):
self.messages: List[MailMessage] = messages
self.capabilities: List[str] = []
def __enter__(self): def __enter__(self):
return self return self
def __exit__(self, exc_type, exc_val, exc_tb): def __exit__(self, exc_type, exc_val, exc_tb):
pass pass
def __init__(self, messages):
self.messages: List[MailMessage] = messages
def authenticate(self, mechanism, authobject): def authenticate(self, mechanism, authobject):
# authobject must be a callable object # authobject must be a callable object
auth_bytes = authobject(None) auth_bytes = authobject(None)
@ -80,12 +81,6 @@ class BogusMailBox(ContextManager):
# Note the non-ascii characters here # Note the non-ascii characters here
UTF_PASSWORD: str = "w57äöüw4b6huwb6nhu" UTF_PASSWORD: str = "w57äöüw4b6huwb6nhu"
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def __init__(self): def __init__(self):
self.messages: List[MailMessage] = [] self.messages: List[MailMessage] = []
self.messages_spam: List[MailMessage] = [] self.messages_spam: List[MailMessage] = []
@ -93,6 +88,12 @@ class BogusMailBox(ContextManager):
self.client = BogusClient(self.messages) self.client = BogusClient(self.messages)
self._host = "" self._host = ""
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def updateClient(self): def updateClient(self):
self.client = BogusClient(self.messages) self.client = BogusClient(self.messages)
@ -648,6 +649,7 @@ class TestMail(DirectoriesMixin, TestCase):
def test_handle_mail_account_tag_gmail(self): def test_handle_mail_account_tag_gmail(self):
self.bogus_mailbox._host = "imap.gmail.com" self.bogus_mailbox._host = "imap.gmail.com"
self.bogus_mailbox.client.capabilities = ["X-GM-EXT-1"]
account = MailAccount.objects.create( account = MailAccount.objects.create(
name="test", name="test",