diff options
author | Hugo Hörnquist <hugo@lysator.liu.se> | 2022-10-31 08:10:04 +0100 |
---|---|---|
committer | Hugo Hörnquist <hugo@lysator.liu.se> | 2022-10-31 08:51:15 +0100 |
commit | e89ec3a1e1a94bab33ca6f4bcdd2147de52f2c2c (patch) | |
tree | 7317334ec370fed7b435e3ea452757784c494c06 | |
parent | Introduce types. (diff) | |
download | mu4web-e89ec3a1e1a94bab33ca6f4bcdd2147de52f2c2c.tar.gz mu4web-e89ec3a1e1a94bab33ca6f4bcdd2147de52f2c2c.tar.xz |
Move stuff to sub-files.
-rw-r--r-- | html_render.py | 45 | ||||
-rw-r--r-- | main.py | 110 | ||||
-rw-r--r-- | mu.py | 66 |
3 files changed, 114 insertions, 107 deletions
diff --git a/html_render.py b/html_render.py new file mode 100644 index 0000000..533ae7c --- /dev/null +++ b/html_render.py @@ -0,0 +1,45 @@ +import html +from typing import ( + TypeAlias, + Union, + Callable, + Optional, + cast, +) + +HTML: TypeAlias = Union[tuple, list, Callable[[], str], None, + str, int, float] + + +standalones = ['hr', 'br', 'meta'] + + +def _render_document(document: HTML) -> str: + if type(document) == tuple: + tag, *body = document + if body and type(body[0]) == dict: + print(body[0]) + attributes = ' '.join(f'{a}="{html.escape(b)}"' + for a, b in body[0].items()) + body = body[1:] + start = f'<{tag} {attributes}>' + else: + start = f'<{tag}>' + if tag in standalones: + return start + else: + items = ''.join(_render_document(b) for b in body) + return start + f'{items}</{tag}>' + elif callable(document): + return str(document()) + elif type(document) == list: + return ''.join(_render_document(e) for e in document) + elif document is None: + return '' + else: + # strings, and everything else + return html.escape(str(document)) + + +def render_document(document: HTML) -> str: + return '<!doctype html>\n' + _render_document(document) @@ -1,47 +1,21 @@ -import subprocess -import email -import email.message from email.message import EmailMessage from email.headerregistry import Address -from subprocess import PIPE -import html -from email.parser import BytesParser -import email.policy from urllib.parse import urlparse, urlencode, parse_qs from http.cookies import BaseCookie import http.cookies import password from password import Passwords from uuid import uuid4 -import xml.dom.minidom -import xml.dom import os from typing import ( - TypeAlias, - Union, - Callable, Optional, cast, ) +from mu import mu_search, get_mail +from html_render import HTML, render_document from http.server import HTTPServer, BaseHTTPRequestHandler -HTML: TypeAlias = Union[tuple, list, Callable[[], str], None, - str, int, float] - -parser = BytesParser(policy=email.policy.default) - - -def get_mail(id: str) -> email.message.Message: - cmd = subprocess.run(['mu', 'find', '-u', f'i:{id}', - '--fields', 'l'], - stdout=PIPE) - filename = cmd.stdout.decode('UTF-8').strip() - - with open(filename, "rb") as f: - mail = parser.parse(f) - return mail - def mailto(addr: str) -> HTML: return ('a', {'href': f'mailto:{addr}'}, addr) @@ -66,40 +40,6 @@ def header_format(key: str, value) -> HTML: return value -standalones = ['hr', 'br', 'meta'] - - -def _render_document(document: HTML) -> str: - if type(document) == tuple: - tag, *body = document - if body and type(body[0]) == dict: - print(body[0]) - attributes = ' '.join(f'{a}="{html.escape(b)}"' - for a, b in body[0].items()) - body = body[1:] - start = f'<{tag} {attributes}>' - else: - start = f'<{tag}>' - if tag in standalones: - return start - else: - items = ''.join(_render_document(b) for b in body) - return start + f'{items}</{tag}>' - elif callable(document): - return str(document()) - elif type(document) == list: - return ''.join(_render_document(e) for e in document) - elif document is None: - return '' - else: - # strings, and everything else - return html.escape(str(document)) - - -def render_document(document: HTML) -> str: - return '<!doctype html>\n' + _render_document(document) - - style: HTML = lambda: """ nav { display: block; @@ -242,51 +182,6 @@ def search_field(q: str) -> HTML: ('input', {'type': 'Submit'})) -class MuError(Exception): - codes = { - 1: 'General Error', - 2: 'No Matches', - 4: 'Database is corrupted' - } - - def __init__(self, returncode: int): - self.returncode: int = returncode - self.msg: str = MuError.codes.get(returncode, 'Unknown Error') - - def __repr__(self): - return f'MuError({self.returncode}, "{self.msg}")' - - -def mu_search(query, sortfield='subject', reverse=False): - if not query: - raise ValueError('Query required for mu_search') - cmdline = ['mu', 'find', - '--format=xml', - query, - '--sortfield', sortfield] - if reverse: - cmdline.append('--reverse') - cmd = subprocess.Popen(cmdline, stdout=subprocess.PIPE) - dom = xml.dom.minidom.parse(cmd.stdout) - if returncode := cmd.wait(): - raise MuError(returncode) - - message_list = [] - messages = dom.childNodes[0] - assert messages.localName == 'messages' - for message in messages.childNodes: - msg_dict = {} - if message.nodeType != xml.dom.Node.ELEMENT_NODE: - continue - for kv in message.childNodes: - if kv.nodeType != xml.dom.Node.ELEMENT_NODE: - continue - msg_dict[kv.localName] = kv.childNodes[0].data - message_list.append(msg_dict) - - return message_list - - def search_result(q, by, reverse): keys = ['From', 'To', 'Subject', 'Date', 'Size', 'Maildir', 'Msgid'] @@ -457,6 +352,7 @@ class Handler(BaseHTTPRequestHandler): self.send_header('location', '/') else: self.send_response(302) + self.send_header('location', '/') self.end_headers() @@ -0,0 +1,66 @@ +import email.message +import email.policy +from email.parser import BytesParser +import subprocess +from subprocess import PIPE +import xml.dom.minidom +import xml.dom + + +parser = BytesParser(policy=email.policy.default) + + +def get_mail(id: str) -> email.message.Message: + cmd = subprocess.run(['mu', 'find', '-u', f'i:{id}', + '--fields', 'l'], + stdout=PIPE) + filename = cmd.stdout.decode('UTF-8').strip() + + with open(filename, "rb") as f: + mail = parser.parse(f) + return mail + + +class MuError(Exception): + codes = { + 1: 'General Error', + 2: 'No Matches', + 4: 'Database is corrupted' + } + + def __init__(self, returncode: int): + self.returncode: int = returncode + self.msg: str = MuError.codes.get(returncode, 'Unknown Error') + + def __repr__(self): + return f'MuError({self.returncode}, "{self.msg}")' + + +def mu_search(query, sortfield='subject', reverse=False): + if not query: + raise ValueError('Query required for mu_search') + cmdline = ['mu', 'find', + '--format=xml', + query, + '--sortfield', sortfield] + if reverse: + cmdline.append('--reverse') + cmd = subprocess.Popen(cmdline, stdout=subprocess.PIPE) + dom = xml.dom.minidom.parse(cmd.stdout) + if returncode := cmd.wait(): + raise MuError(returncode) + + message_list = [] + messages = dom.childNodes[0] + assert messages.localName == 'messages' + for message in messages.childNodes: + msg_dict = {} + if message.nodeType != xml.dom.Node.ELEMENT_NODE: + continue + for kv in message.childNodes: + if kv.nodeType != xml.dom.Node.ELEMENT_NODE: + continue + msg_dict[kv.localName] = kv.childNodes[0].data + message_list.append(msg_dict) + + return message_list |