#!/bin/bash
# Lodewijk-blokkade (5 oktober 2026): zet de blokkadelijsten uit /etc/rspamd/local.d/maps na controle klaar
# voor Exim in /etc/exim.lodewijk (zie /etc/exim.acl_check_recipient.pre.conf). Bewerken gebeurt alleen in
# de Rspamd-map; dit script maakt er een kopie van die Exim veilig kan lezen.
# Een lijst met een fout (een regex die niet compileert, een regel die alles zou raken, een kapotte regel in
# een adres-, domein- of IP-lijst) gaat NIET door: dan blijft de vorige goede kopie gelden en komt er een
# melding. Zo kan een tikfout nooit alle mail laten weigeren.
# Draait elke vijf minuten via /etc/cron.d/lodewijk-blokkade; na het bewerken van een lijst kun je hem ook zelf
# draaien. Uitvoer: /var/log/lodewijk-blokkade.log. Bij een nieuwe fout (en bij herstel) een mail naar MELDEN.
set -u
BRON=${BRON:-/etc/rspamd/local.d/maps}
DOEL=${DOEL:-/etc/exim.lodewijk}
LOG=${LOG:-/var/log/lodewijk-blokkade.log}
MELDEN=${MELDEN:-root}
STAAT="$DOEL/.status"
EXIM=$(command -v exim || echo /usr/sbin/exim)
mkdir -p "$DOEL" && chmod 755 "$DOEL"
fouten=()
log() { printf '%s %s\n' "$(date '+%F %T')" "$*" >> "$LOG"; }

# Regels zonder commentaar en lege regels, inline commentaar (spatie + #) eraf.
regels() { sed -e 's/[[:space:]]#.*$//' -e 's/[[:space:]]*$//' "$1" | grep -v '^[[:space:]]*\(#\|$\)'; }

controleer_regex() { # bestand, onschuldige voorbeelden (newline-gescheiden)
  local f=$1 goed=$2 uit
  # Exact dezelfde omzetting als in de hooks; een regex die niet compileert geeft "Failed". De expressie gaat
  # via stdin, want als argument staat Exim maar 256 tekens toe.
  uit=$(printf '%s\n' "\${if forany{<\n \${readfile{$f}}}{and{{!match{\$item}{\N^\s*(#|\$)\N}}{match{$goed}{\${if match{\$item}{\N^/(.*)/([a-tv-z]*)(u?)([a-z]*)\$\N}{\${if eq{\$3}{u}{(*UTF)}{}}(?m\$2\$4)\$1}{(?m)\$item}}}}}}{RAAKT}{SCHOON}}" \
    | "$EXIM" -be 2>&1 | sed 's/^> *//' | grep -v "cwd=\|^[0-9-]* [0-9:]* \|^$")
  case "$uit" in
    SCHOON) return 0 ;;
    RAAKT) echo "een regel raakt ook gewone afzenders (zoals gmail.com): te breed"; return 1 ;;
    *) echo "Exim kan een regel niet lezen: $(echo "$uit" | head -2 | tr '\n' ' ')"; return 1 ;;
  esac
}

for f in block_sender_ips.map block_sender_addresses.map block_sender_domains.map block_sender_hosts.map block_replyto_domains.map bad_tlds.re bad_replyto_domains.re bad_from_headers.re; do
  src="$BRON/$f"
  if [ ! -r "$src" ]; then fouten+=("$f: ontbreekt of is niet leesbaar in $BRON"); continue; fi
  if grep -q '^[[:space:]]\+[^[:space:]]' "$src"; then fouten+=("$f: een regel begint met een spatie"); continue; fi
  probleem=""
  case "$f" in
    block_sender_ips.map)
      probleem=$(regels "$src" | grep -Evx '([0-9]{1,3}\.){3}[0-9]{1,3}(/[0-9]{1,2})?|[0-9a-fA-F:]*:[0-9a-fA-F:.]*(/[0-9]{1,3})?' | head -1) ;;
    block_sender_addresses.map)
      probleem=$(regels "$src" | grep -Evx '[^@[:space:]:]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]+' | head -1) ;;
    block_sender_domains.map|block_sender_hosts.map|block_replyto_domains.map)
      probleem=$(regels "$src" | grep -Evx '[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+' | head -1) ;;
    bad_tlds.re|bad_replyto_domains.re)
      r=$(controleer_regex "$src" "gmail.com\nlodewijk.frl\nhogerheide.nl\nziggo.nl\noutlook.com\nhollandskroon.nl") || probleem="$r" ;;
    bad_from_headers.re)
      r=$(controleer_regex "$src" "Jan Jansen <jan.jansen@gmail.com>\nGemeente Hollands Kroon <info@hollandskroon.nl>\ninfo@lodewijk.frl") || probleem="$r" ;;
  esac
  if [ -n "$probleem" ]; then fouten+=("$f: $probleem"); continue; fi
  if ! cmp -s "$src" "$DOEL/$f"; then
    tmp=$(mktemp "$DOEL/.$f.XXXXXX") && cp "$src" "$tmp" && chmod 644 "$tmp" && mv -f "$tmp" "$DOEL/$f" && log "bijgewerkt: $f"
  fi
done

oud=$(cat "$STAAT" 2>/dev/null || echo ok)
if [ ${#fouten[@]} -gt 0 ]; then
  tekst=$(printf '%s\n' "${fouten[@]}")
  log "FOUT, vorige kopie blijft gelden: $(echo "$tekst" | tr '\n' ';')"
  echo "$tekst" >&2
  if [ "$oud" != "fout:$(echo "$tekst" | md5sum | cut -c1-12)" ]; then
    {
      printf 'To: %s
Subject: Spamblokkade %s: lijst met fout niet doorgezet

' "$MELDEN" "$(hostname)"
      printf 'Op %s gaat een blokkadelijst niet door naar Exim. De vorige goede kopie blijft gelden, de mail loopt gewoon.

%s

Pas de lijst aan in %s; dit script controleert hem elke vijf minuten opnieuw.
' "$(hostname)" "$tekst" "$BRON"
    } | "$EXIM" -odi -f "root@$(hostname)" -t 2>/dev/null
    echo "fout:$(echo "$tekst" | md5sum | cut -c1-12)" > "$STAAT"
  fi
  exit 1
fi
if [ "$oud" != "ok" ]; then log "hersteld: alle lijsten weer in orde"; echo ok > "$STAAT"; fi
exit 0
