aboutsummaryrefslogtreecommitdiff
path: root/ctec/logic.py
blob: 1769e47abc56c71b60b5ccd273876d88b89f8842 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import imaplib
import mailbox
import pathlib
import pprint
import re
from typing import List, Union, Tuple

from . import import_or_install, imap_response

mailbox.Maildir.colon = '!'

FLAGS = re.compile(rb'FLAGS \(([^)]+?)\)')

def percent_encode(c: str) -> str:
    return '%' + hex(ord(c))[2:]

def clean_folder_name(folder_name: str, separator: str) -> str:
    folder_name = folder_name.replace('%', percent_encode('%'))
    folder_name = folder_name.replace('.', percent_encode('.'))
    folder_name = folder_name.replace(separator, '.')
    return folder_name

def dirty_folder_name(folder_name: str, separator: str = '/') -> str:
    folder_name = folder_name.replace('.', separator)
    folder_name = folder_name.replace(percent_encode('.'), '.')
    folder_name = folder_name.replace(percent_encode('%'), '%')
    return folder_name

class Account:
    def __init__(self, address: str, info: dict):
        appdirs = import_or_install('appdirs')
        data_dir = pathlib.Path(appdirs.user_data_dir(appname='ctec', appauthor=False))
        self.address = address
        self.mailbox = mailbox.Maildir(data_dir / address)
        self.info = info
        self.connection = imaplib.IMAP4_SSL(self.info['imap host'])
        self.connection.login(self.address, self.info['password'])

    def __del__(self):
        self.connection.logout()

    def fetch_folders(self):
        folder_list: List[bytes]
        typ, folder_list = self.connection.list()
        for folder in folder_list:
            folder_info = imap_response.List.parse(folder)
            if folder_info.delimiter != '/':
                raise NotImplementedError(f'who the hell uses {repr(folder_info.delimiter)} as a delimiter')
            self.mailbox.add_folder(clean_folder_name(folder_info.name, folder_info.delimiter))

    def fetch_inbox(self):
        with imaplib.IMAP4_SSL(self.info['imap host']) as M:
            M.login(self.address, self.info['password'])
            inbox = self.mailbox.add_folder('Inbox')
            M.select()
            typ, data = M.search(None, 'ALL')
            for num in data[0].split():
                typ, data = M.fetch(num, '(FLAGS RFC822)')
                for prefix, message in data[:-1]:
                    flags = FLAGS.search(prefix).group(1).split()
                    message = mailbox.MaildirMessage(message)
                    print(message['Subject'], flags)
                    if rb'\Seen' in flags:
                        message.add_flag('S')
                        message.set_subdir('cur')
                    if 'Message-ID' in message:
                        message_id = message['Message-ID'].strip()
                    else:
                        print(message)
                        raise KeyError('No message ID header')
                    if not any(x['Message-ID'].strip() == message_id for x in inbox):
                        inbox.add(message)
            M.close()

    def folders(self) -> List[Tuple[str, mailbox.Maildir]]:
        return [(folder, self.mailbox.get_folder(folder)) for folder in self.mailbox.list_folders()]

    def inbox(self) -> mailbox.Maildir:
        return self.mailbox.add_folder('Inbox')