diff --git a/core/admin/mailu/internal/views.py b/core/admin/mailu/internal/views.py index e784a062..103dddd6 100644 --- a/core/admin/mailu/internal/views.py +++ b/core/admin/mailu/internal/views.py @@ -6,6 +6,7 @@ import flask import flask_login import base64 import urllib +import datetime @internal.route("/auth/email") @@ -128,3 +129,30 @@ def dovecot_sieve_data(user_email): user = models.User.query.get(user_email) or flask.abort(404) return flask.jsonify(flask.render_template("default.sieve", user=user)) + +@internal.route("/fetch") +def fetch_list(): + return flask.jsonify([ + { + "id": fetch.id, + "tls": fetch.tls, + "keep": fetch.keep, + "user_email": fetch.user_email, + "protocol": fetch.protocol, + "host": fetch.host, + "port": fetch.port, + "username": fetch.username, + "password": fetch.password + } for fetch in models.Fetch.query.all() + ]) + + +@internal.route("/fetch/", methods=["POST"]) +def fetch_done(fetch_id): + fetch = models.Fetch.query.get(fetch_id) or flask.abort(404) + fetch.last_check = datetime.datetime.now() + fetch.error_message = str(flask.request.get_json()) + db.session.add(fetch) + db.session.commit() + return "" + diff --git a/docs/compose/docker-compose.yml b/docs/compose/docker-compose.yml index 1a171af5..6f2da078 100644 --- a/docs/compose/docker-compose.yml +++ b/docs/compose/docker-compose.yml @@ -102,5 +102,3 @@ services: image: mailu/fetchmail:$VERSION restart: always env_file: .env - volumes: - - "$ROOT/data:/data" diff --git a/services/fetchmail/Dockerfile b/services/fetchmail/Dockerfile index a44c6e50..33f8a7de 100644 --- a/services/fetchmail/Dockerfile +++ b/services/fetchmail/Dockerfile @@ -1,7 +1,9 @@ -FROM python:alpine +FROM python:3-alpine -RUN apk add --no-cache fetchmail ca-certificates +RUN apk add --no-cache fetchmail ca-certificates \ + && pip install requests COPY fetchmail.py /fetchmail.py +USER fetchmail CMD ["/fetchmail.py"] diff --git a/services/fetchmail/fetchmail.py b/services/fetchmail/fetchmail.py index 6aeea3e7..8e006f84 100755 --- a/services/fetchmail/fetchmail.py +++ b/services/fetchmail/fetchmail.py @@ -1,12 +1,12 @@ #!/usr/bin/env python -import sqlite3 import time import os import tempfile import shlex import subprocess import re +import requests FETCHMAIL = """ @@ -15,6 +15,7 @@ fetchmail -N \ -f {} """ + RC_LINE = """ poll "{host}" proto {protocol} port {port} user "{username}" password "{password}" @@ -24,10 +25,12 @@ poll "{host}" proto {protocol} port {port} sslproto 'AUTO' """ + def extract_host_port(host_and_port, default_port): host, _, port = re.match('^(.*)(:([0-9]*))?$', host_and_port).groups() return host, int(port) if port else default_port + def escape_rc_string(arg): return arg.replace("\\", "\\\\").replace('"', '\\"') @@ -41,30 +44,26 @@ def fetchmail(fetchmailrc): return output -def run(connection, cursor, debug): - cursor.execute(""" - SELECT user_email, protocol, host, port, tls, username, password, keep - FROM fetch - """) +def run(debug): + fetches = requests.get("http://admin/internal/fetch").json() smtphost, smtpport = extract_host_port(os.environ.get("HOST_SMTP", "smtp"), None) if smtpport is None: smtphostport = smtphost else: smtphostport = "%s/%d" % (smtphost, smtpport) - for line in cursor.fetchall(): + for fetch in fetches: fetchmailrc = "" - user_email, protocol, host, port, tls, username, password, keep = line options = "options antispam 501, 504, 550, 553, 554" - options += " ssl" if tls else "" - options += " keep" if keep else " fetchall" + options += " ssl" if fetch["tls"] else "" + options += " keep" if fetch["keep"] else " fetchall" fetchmailrc += RC_LINE.format( - user_email=escape_rc_string(user_email), - protocol=protocol, - host=escape_rc_string(host), - port=port, + user_email=escape_rc_string(fetch["user_email"]), + protocol=fetch["protocol"], + host=escape_rc_string(fetch["host"]), + port=fetch["port"], smtphost=smtphostport, - username=escape_rc_string(username), - password=escape_rc_string(password), + username=escape_rc_string(fetch["username"]), + password=escape_rc_string(fetch["password"]), options=options ) if debug: @@ -77,26 +76,20 @@ def run(connection, cursor, debug): # No mail is not an error if not error_message.startswith("fetchmail: No mail"): print(error_message) - user_info = "for %s at %s" % (user_email, host) + user_info = "for %s at %s" % (fetch["user_email"], fetch["host"]) # Number of messages seen is not a error as well if ("messages" in error_message and "(seen " in error_message and user_info in error_message): print(error_message) finally: - cursor.execute(""" - UPDATE fetch SET error=?, last_check=datetime('now') - WHERE user_email=? - """, (error_message.split("\n")[0], user_email)) - connection.commit() + requests.post("http://admin/internal/fetch/{}".format(fetch["id"]), + json=error_message.split("\n")[0] + ) if __name__ == "__main__": - debug = os.environ.get("DEBUG", None) == "True" - db_path = os.environ.get("DB_PATH", "/data/main.db") - connection = sqlite3.connect(db_path) while True: - cursor = connection.cursor() - run(connection, cursor, debug) - cursor.close() time.sleep(int(os.environ.get("FETCHMAIL_DELAY", 60))) + run(os.environ.get("DEBUG", None) == "True") +