Initial status for developed files on dagda
This commit is contained in:
+190
@@ -0,0 +1,190 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Upload en activeer de Sieve-mailrule op australius.nl via ManageSieve (RFC 5804).
|
||||
Poort: 4190 met STARTTLS.
|
||||
|
||||
Gebruik: python3 upload_sieve.py
|
||||
"""
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
import sys
|
||||
import base64
|
||||
import config
|
||||
from pathlib import Path
|
||||
SCRIPT_NAME = "mailrules"
|
||||
SCRIPT_FILE = Path(__file__).parent / "mailrules.sieve"
|
||||
|
||||
# Als fileinto-paden "INBOX." als prefix nodig hebben op deze server:
|
||||
# Zet SIEVE_PREFIX op "INBOX." en het script past de paden automatisch aan.
|
||||
# Zet op "" als de server paden zonder prefix accepteert (meest gangbaar).
|
||||
SIEVE_PREFIX = ""
|
||||
|
||||
|
||||
class ManageSieveClient:
|
||||
"""Minimale ManageSieve-client (RFC 5804)."""
|
||||
|
||||
def __init__(self, host: str, port: int):
|
||||
self._sock = None
|
||||
self._host = host
|
||||
self._port = port
|
||||
|
||||
def connect(self):
|
||||
raw = socket.create_connection((self._host, self._port), timeout=15)
|
||||
self._sock = raw
|
||||
greeting = self._readline()
|
||||
if not greeting.startswith("OK"):
|
||||
raise ConnectionError(f"Onverwachte greeting: {greeting!r}")
|
||||
# Lees eventuele capability-regels na de greeting
|
||||
self._read_capabilities()
|
||||
|
||||
def starttls(self):
|
||||
self._send("STARTTLS")
|
||||
resp = self._readline()
|
||||
if not resp.startswith("OK"):
|
||||
raise ConnectionError(f"STARTTLS geweigerd: {resp!r}")
|
||||
context = ssl.create_default_context()
|
||||
self._sock = context.wrap_socket(self._sock, server_hostname=self._host)
|
||||
# Nieuwe capabilities na TLS
|
||||
self._read_capabilities()
|
||||
|
||||
def authenticate(self, username: str, password: str):
|
||||
creds = base64.b64encode(f"\x00{username}\x00{password}".encode()).decode()
|
||||
self._send(f'AUTHENTICATE "PLAIN" "{creds}"')
|
||||
resp = self._readline()
|
||||
if not resp.startswith("OK"):
|
||||
raise PermissionError(f"Authenticatie mislukt: {resp!r}")
|
||||
|
||||
def put_script(self, name: str, content: str):
|
||||
encoded = content.encode("utf-8")
|
||||
self._send(f'PUTSCRIPT "{name}" {{{len(encoded)}+}}')
|
||||
self._sock.sendall(encoded)
|
||||
resp = self._readline()
|
||||
if not resp.startswith("OK"):
|
||||
raise RuntimeError(f"PUTSCRIPT mislukt: {resp!r}")
|
||||
|
||||
def set_active(self, name: str):
|
||||
self._send(f'SETACTIVE "{name}"')
|
||||
resp = self._readline()
|
||||
if not resp.startswith("OK"):
|
||||
raise RuntimeError(f"SETACTIVE mislukt: {resp!r}")
|
||||
|
||||
def list_scripts(self) -> list[str]:
|
||||
self._send("LISTSCRIPTS")
|
||||
scripts = []
|
||||
while True:
|
||||
line = self._readline()
|
||||
if line.startswith("OK"):
|
||||
break
|
||||
scripts.append(line)
|
||||
return scripts
|
||||
|
||||
def logout(self):
|
||||
try:
|
||||
self._send("LOGOUT")
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
self._sock.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _send(self, cmd: str):
|
||||
self._sock.sendall((cmd + "\r\n").encode())
|
||||
|
||||
def _readline(self) -> str:
|
||||
buf = b""
|
||||
while not buf.endswith(b"\n"):
|
||||
chunk = self._sock.recv(1)
|
||||
if not chunk:
|
||||
break
|
||||
buf += chunk
|
||||
return buf.decode("utf-8", errors="replace").strip()
|
||||
|
||||
def _read_capabilities(self):
|
||||
"""Lees en negeer capability-regels tot een lege regel of einde."""
|
||||
# Capabilities eindigen met een lege regel of worden gevolgd door authenticatie
|
||||
# We lezen tot we iets tegenkomen dat niet op een capability lijkt
|
||||
# (dit is een vereenvoudiging; volledige RFC 5804 parsing is complexer)
|
||||
pass
|
||||
|
||||
|
||||
def apply_prefix(script: str, prefix: str) -> str:
|
||||
"""Voeg SIEVE_PREFIX toe aan alle fileinto-paden als dat nodig is."""
|
||||
if not prefix:
|
||||
return script
|
||||
import re
|
||||
def add_prefix(m):
|
||||
path = m.group(1)
|
||||
if path.startswith(prefix):
|
||||
return m.group(0) # al aanwezig
|
||||
return f'fileinto "{prefix}{path}"'
|
||||
return re.sub(r'fileinto "([^"]+)"', add_prefix, script)
|
||||
|
||||
|
||||
def run():
|
||||
if not SCRIPT_FILE.exists():
|
||||
print(f"Script niet gevonden: {SCRIPT_FILE}")
|
||||
sys.exit(1)
|
||||
|
||||
script_content = SCRIPT_FILE.read_text(encoding="utf-8")
|
||||
script_content = apply_prefix(script_content, SIEVE_PREFIX)
|
||||
|
||||
cfg = config.load()
|
||||
|
||||
print(f"Script: {SCRIPT_FILE.name} ({len(script_content)} bytes)")
|
||||
print(f"Server: {cfg.sieve_host}:{cfg.sieve_port}")
|
||||
print(f"Account:{cfg.username}")
|
||||
print(f"Naam: {SCRIPT_NAME}\n")
|
||||
|
||||
client = ManageSieveClient(cfg.sieve_host, cfg.sieve_port)
|
||||
|
||||
print("Verbinden ...")
|
||||
try:
|
||||
client.connect()
|
||||
print(" STARTTLS ...")
|
||||
client.starttls()
|
||||
print(" Authenticeren ...")
|
||||
client.authenticate(cfg.username, cfg.password)
|
||||
except Exception as e:
|
||||
print(f"Verbinding mislukt: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# Toon bestaande scripts
|
||||
scripts = client.list_scripts()
|
||||
if scripts:
|
||||
print(f"\nBestaande scripts op server:")
|
||||
for s in scripts:
|
||||
print(f" {s}")
|
||||
else:
|
||||
print("\nGeen bestaande scripts.")
|
||||
|
||||
# Bevestiging vragen
|
||||
print(f"\nScript '{SCRIPT_NAME}' wordt geüpload en geactiveerd.")
|
||||
bevestig = input("Typ JA om door te gaan: ").strip()
|
||||
if bevestig != "JA":
|
||||
print("Afgebroken.")
|
||||
client.logout()
|
||||
sys.exit(0)
|
||||
|
||||
print("\nUploaden ...")
|
||||
try:
|
||||
client.put_script(SCRIPT_NAME, script_content)
|
||||
print(f" ✓ {SCRIPT_NAME} geüpload")
|
||||
client.set_active(SCRIPT_NAME)
|
||||
print(f" ✓ {SCRIPT_NAME} geactiveerd")
|
||||
except Exception as e:
|
||||
print(f" ✗ Mislukt: {e}")
|
||||
client.logout()
|
||||
sys.exit(1)
|
||||
|
||||
client.logout()
|
||||
print("\nKlaar. Nieuwe inkomende mail wordt nu automatisch gesorteerd.")
|
||||
print(f"\nAls mail niet aankomt in de verwachte mappen:")
|
||||
print(f" 1. Controleer of alle mappen bestaan (maak_mappen.py)")
|
||||
print(f" 2. Probeer SIEVE_PREFIX = \"INBOX.\" in dit script")
|
||||
print(f" 3. Controleer server-logs via webhosting-paneel")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
Reference in New Issue
Block a user