aboutsummaryrefslogtreecommitdiff
path: root/ctec/logic.py
diff options
context:
space:
mode:
Diffstat (limited to 'ctec/logic.py')
-rw-r--r--ctec/logic.py119
1 files changed, 93 insertions, 26 deletions
diff --git a/ctec/logic.py b/ctec/logic.py
index 1769e47..d151a0f 100644
--- a/ctec/logic.py
+++ b/ctec/logic.py
@@ -1,15 +1,13 @@
import imaplib
import mailbox
import pathlib
-import pprint
-import re
-from typing import List, Union, Tuple
+from typing import List, Tuple
from . import import_or_install, imap_response
mailbox.Maildir.colon = '!'
-FLAGS = re.compile(rb'FLAGS \(([^)]+?)\)')
+MESSAGE_DOWNLOAD_BATCH = 1
def percent_encode(c: str) -> str:
return '%' + hex(ord(c))[2:]
@@ -48,29 +46,98 @@ class Account:
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()
+ def fetch_folder(self, folder_name: str):
+ folder = self.mailbox.add_folder(folder_name)
+ message_id_to_key = dict((message['Message-ID'], key) for key, message in folder.iteritems() if 'Message-ID' in message)
+ typ, count_data = self.connection.select(dirty_folder_name(folder_name))
+ if typ != 'OK':
+ print(typ, count_data)
+ count = int(count_data[0].decode('ASCII'))
+ needs_fetching = []
+ if count > 0:
+ typ, data = self.connection.fetch('1:*', '(FLAGS ENVELOPE)')
+ if typ != 'OK':
+ print(typ, data)
+ pending: List[bytes] = []
+ for fetched_line in data:
+ if isinstance(fetched_line, tuple):
+ pending.append(b'\r\n'.join(fetched_line))
+ elif isinstance(fetched_line, bytes):
+ pending.append(fetched_line)
+ else:
+ raise TypeError(f'what the hell is a {repr(fetched_line)} and why is it in the fetch response')
+ try:
+ parsed_data = imap_response.MessageData.parse(b''.join(pending))
+ number = parsed_data.number
+ if parsed_data.envelope is None:
+ print('hold the fuck up where did that envelope go', parsed_data)
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()
+ message_id = parsed_data.envelope.get('message_id', None)
+ if message_id is None:
+ print('no message ID for', parsed_data)
+ elif message_id in message_id_to_key:
+ message: mailbox.MaildirMessage = folder[message_id_to_key[message_id]]
+ flags_list = parsed_data.flags or []
+ flags = ''
+ if r'\Seen' in flags_list:
+ flags += 'S'
+ if r'\Answered' in flags_list:
+ flags += 'R' # Replied to
+ if r'\Flagged' in flags_list:
+ flags += 'F'
+ if r'\Deleted' in flags_list:
+ flags += 'T' # Trashed
+ if r'\Draft' in flags_list:
+ flags += 'D'
+ message.set_flags(flags)
+ else:
+ needs_fetching.append(number)
+ pending = []
+ except ValueError:
+ continue
+ if len(pending) > 0:
+ imap_response.MessageData.parse(b''.join(pending))
+
+ if len(needs_fetching) > 0:
+ for fetch_start in range(0, len(needs_fetching), MESSAGE_DOWNLOAD_BATCH):
+ typ, data = self.connection.fetch(','.join(str(x) for x in needs_fetching[fetch_start:fetch_start + MESSAGE_DOWNLOAD_BATCH]), '(FLAGS BODY.PEEK[])')
+ if typ != 'OK':
+ print(typ, data)
+ pending = []
+ for fetched_line in data:
+ if isinstance(fetched_line, tuple):
+ pending.append(b'\r\n'.join(fetched_line))
+ elif isinstance(fetched_line, bytes):
+ pending.append(fetched_line)
+ else:
+ raise TypeError(f'what the hell is a {repr(fetched_line)} and why is it in the fetch response')
+ try:
+ parsed_data = imap_response.MessageData.parse(b''.join(pending))
+ if parsed_data.body_all_sections is None:
+ print('hold the fuck up where did that body go', parsed_data)
+ else:
+ message = mailbox.MaildirMessage(parsed_data.body_all_sections)
+ flags_list = parsed_data.flags or []
+ flags = ''
+ if r'\Seen' in flags_list:
+ flags += 'S'
+ if r'\Answered' in flags_list:
+ flags += 'R' # Replied to
+ if r'\Flagged' in flags_list:
+ flags += 'F'
+ if r'\Deleted' in flags_list:
+ flags += 'T' # Trashed
+ if r'\Draft' in flags_list:
+ flags += 'D'
+ message.set_flags(flags)
+ folder.add(message)
+ pending = []
+ except ValueError:
+ continue
+ if len(pending) > 0:
+ imap_response.MessageData.parse(b''.join(pending))
+
+ self.connection.close()
def folders(self) -> List[Tuple[str, mailbox.Maildir]]:
return [(folder, self.mailbox.get_folder(folder)) for folder in self.mailbox.list_folders()]