109 lines
3.5 KiB
Python
109 lines
3.5 KiB
Python
# Copyright (C) 2020 by Maike <maike@systemli.org>
|
|
# Copyright (C) 2020 by Cathy Hu <cathy.hu@fau.de>
|
|
# Copyright (C) 2020, 2023 by Thomas Lindner <tom@dl6tom.de>
|
|
# Copyright (C) 2020 by Martin Rey <martin.rey@mailbox.org>
|
|
#
|
|
# SPDX-License-Identifier: 0BSD
|
|
|
|
from argparse import ArgumentParser
|
|
from asyncio import run as asyncio_run
|
|
from email.parser import BytesParser
|
|
from email.policy import default
|
|
from email.utils import parseaddr
|
|
from logging import getLogger
|
|
from re import sub
|
|
from sys import stdin
|
|
|
|
from fastapi import status
|
|
from ormantic import NoMatch
|
|
from pytoml import load
|
|
from requests import post
|
|
|
|
from kibicara.config import config
|
|
from kibicara.platforms.email.model import Email, EmailSubscriber
|
|
|
|
logger = getLogger(__name__)
|
|
|
|
|
|
class Main:
|
|
def __init__(self):
|
|
parser = ArgumentParser()
|
|
parser.add_argument(
|
|
"-f",
|
|
"--config",
|
|
dest="configfile",
|
|
default="/etc/kibicara.conf",
|
|
help="path to config file",
|
|
)
|
|
# the MDA passes the recipient address as command line argument
|
|
parser.add_argument("recipient")
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
with open(args.configfile) as configfile:
|
|
config.update(load(configfile))
|
|
except FileNotFoundError:
|
|
# run with default config
|
|
pass
|
|
|
|
# extract email from the recipient
|
|
email_name = args.recipient.lower()
|
|
|
|
asyncio_run(self.__run(email_name))
|
|
|
|
async def __run(self, email_name):
|
|
try:
|
|
email = await Email.get(name=email_name)
|
|
except NoMatch:
|
|
logger.error("No recipient with this name")
|
|
exit(1)
|
|
|
|
# read mail from STDIN and parse to EmailMessage object
|
|
message = BytesParser(policy=default).parsebytes(stdin.buffer.read())
|
|
|
|
sender = ""
|
|
if message.get("sender"):
|
|
sender = message.get("sender")
|
|
elif message.get("from"):
|
|
sender = message.get("from")
|
|
else:
|
|
logger.error("No Sender of From header")
|
|
exit(1)
|
|
|
|
sender = parseaddr(sender)[1]
|
|
if not sender:
|
|
logger.error("Could not parse sender")
|
|
exit(1)
|
|
|
|
maybe_subscriber = await EmailSubscriber.filter(email=sender).all()
|
|
if len(maybe_subscriber) != 1 or maybe_subscriber[0].hood.id != email.hood.id:
|
|
logger.error("Not a subscriber")
|
|
exit(1)
|
|
|
|
# extract relevant data from mail
|
|
text = sub(
|
|
r"<[^>]*>",
|
|
"",
|
|
message.get_body(preferencelist=("plain", "html")).get_content(),
|
|
)
|
|
|
|
response = post(
|
|
"{0}/api/hoods/{1}/email/messages/".format(
|
|
config["root_url"], email.hood.pk
|
|
),
|
|
json={"text": text, "secret": email.secret},
|
|
)
|
|
if response.status_code == status.HTTP_201_CREATED:
|
|
exit(0)
|
|
elif response.status_code == status.HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS:
|
|
logger.error("Message was't accepted: {0}".format(text))
|
|
elif response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY:
|
|
logger.error("Malformed request: {0}".format(response.json()))
|
|
elif response.status_code == status.HTTP_401_UNAUTHORIZED:
|
|
logger.error("Wrong API secret. kibicara_mda seems to be misconfigured")
|
|
else:
|
|
logger.error(
|
|
"REST-API failed with response status {0}".format(response.status_code)
|
|
)
|
|
exit(1)
|