#!/usr/bin/env bash
#
# onx-exim-rspamd-integrate — Exim ACL'sine Rspamd spam scan ekle
#
# v84.3: Postfix Rspamd milter (port 11332) ile entegre ama Exim'de yok.
# Gelen tüm mailleri filtresiz kabul ediyor (production'da spam yağmuru).
#
# Exim Rspamd integration:
#   SA-compat protocol (Rspamd worker-normal port 11333) Exim native `spam =`
#   ACL condition'i ile çalışır. Modern milter protokolü Exim'de native
#   değil — SA-compat yeterli (skor + symbols + header inject).
#
# Bu script:
#   1. exim.conf acl_check_data section'ı patch:
#      - authenticated user skip (relay önle)
#      - localhost skip
#      - spam = nobody:11333 (Rspamd scan, defer_ok timeout tolerant)
#      - X-Spam-Score / X-Spam-Bar / X-Spam-Report header inject (warn)
#      - score >= 15 → reject (deny)
#   2. spamd_address eklenir (Rspamd connection)
#   3. exim -bV syntax check + restart
#
# Idempotent — marker `# v84.3:` ile re-run safe.

set -uo pipefail
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
source "${SCRIPT_DIR}/_lib/common.sh"

require_root
require_cmd systemctl

EXIM_CONF="/etc/exim/exim.conf"
[[ -f "$EXIM_CONF" ]] || onx_die 2 "Exim config yok: $EXIM_CONF (Exim kurulu mu?)"

# Rspamd çalışıyor mu?
if ! systemctl is-active --quiet rspamd 2>/dev/null; then
    onx_die 2 "Rspamd inactive — önce: systemctl enable --now rspamd"
fi

# ─── Idempotent guard ───────────────────────────────────────────────────────
if grep -q "^# v84.3: Rspamd integration" "$EXIM_CONF"; then
    # Zaten patch'li — config tekrar yazma, sadece restart
    systemctl restart exim
    sleep 1
    onx_json_out \
        ok true \
        already_patched true \
        message "Exim Rspamd integration zaten kuruluydu, Exim restart edildi"
    exit 0
fi

# Backup
cp -a "$EXIM_CONF" "${EXIM_CONF}.bak.v84.3.$(date +%s)"

# ─── 1. spamd_address ekle (main section — primary_hostname sonrası) ────────
# Idempotent: önce sil
sed -i '/^spamd_address[[:space:]]*=/d' "$EXIM_CONF"
sed -i '/^primary_hostname[[:space:]]*=/a\
spamd_address = 127.0.0.1 11333 variant=rspamd' "$EXIM_CONF"

# ─── 2. acl_check_data section'ı yeniden yaz ────────────────────────────────
# Mevcut `acl_check_data:` block'unu komple replace.
# Pattern: "acl_check_data:" satırından sonraki section'ı bul, replace.
python3 <<'PYEOF'
import re

CONF = "/etc/exim/exim.conf"
with open(CONF) as f:
    text = f.read()

# Yeni ACL block (Rspamd integration)
new_block = '''acl_check_data:
    # v84.3: Rspamd integration — gelen mail spam check
    # Authenticated user skip (Outlook/webmail relay'i bypass et)
    accept authenticated = *

    # Localhost (panel internal mail) skip
    accept hosts = +relay_from_hosts

    # Rspamd scan — defer_ok=Rspamd timeout/down olursa skip et (graceful)
    warn  spam = nobody:true/defer_ok
          add_header = X-Spam-Score: $spam_score
          add_header = X-Spam-Bar: $spam_bar
          add_header = X-Spam-Report: $spam_report
          add_header = X-Spam-Status: $spam_action
          condition = ${if def:spam_score {1}{0}}

    # High-spam reject (score >= 15 = sure spam)
    deny  message = Message rejected as spam (score $spam_score, threshold 15)
          condition = ${if >{$spam_score_int}{150}{1}{0}}

    accept
'''

# Eski acl_check_data block'unu bul (acl_check_data: satırından sonraki ilk boş satıra kadar)
pattern = re.compile(
    r'acl_check_data:\s*\n(?:[ \t]+.*\n|\n)*?(?=\n(?:[a-z_]+:|begin |# )|\Z)',
    re.MULTILINE
)

if pattern.search(text):
    new_text = pattern.sub(new_block + '\n', text)
else:
    # Block bulunamadıysa: begin acl section'ının altına ekle
    new_text = re.sub(
        r'(begin acl\s*\n)',
        r'\1\n' + new_block + '\n',
        text,
        count=1
    )

with open(CONF, 'w') as f:
    f.write(new_text)
PYEOF

# Idempotent marker satırı ekle (en üste section komentinin altına)
sed -i '/^spamd_address[[:space:]]*=/i\
# v84.3: Rspamd integration enabled' "$EXIM_CONF"

# ─── 3. Syntax check ────────────────────────────────────────────────────────
if ! exim -bV >/dev/null 2>&1; then
    # Rollback
    LATEST_BAK=$(ls -t "${EXIM_CONF}".bak.v84.3.* 2>/dev/null | head -1)
    if [[ -n "$LATEST_BAK" ]]; then
        cp -f "$LATEST_BAK" "$EXIM_CONF"
    fi
    onx_die 3 "exim -bV syntax fail — config rollback ($LATEST_BAK)"
fi

# ─── 4. Restart Exim ────────────────────────────────────────────────────────
if ! systemctl restart exim; then
    onx_die 3 "Exim restart başarısız"
fi
sleep 2

if ! systemctl is-active --quiet exim; then
    onx_die 3 "Exim restart sonrası inactive — journalctl -u exim"
fi

# ─── 5. Verify — Rspamd reachable mı? ────────────────────────────────────────
RSPAMD_OK="false"
( exec 3<>/dev/tcp/127.0.0.1/11333 ) 2>/dev/null && { exec 3<&-; exec 3>&-; RSPAMD_OK="true"; }

onx_json_out \
    ok true \
    already_patched false \
    spamd_address "127.0.0.1:11333" \
    rspamd_reachable "$RSPAMD_OK" \
    acl_section "acl_check_data" \
    spam_threshold "15.0" \
    message "Exim Rspamd ACL inbound aktif (spam scan + X-Spam-* header + score>=15 reject)"
