#!/usr/bin/env bash
# Privileged Maildir filesystem helper for Limristem eMail.
# Invoked as root via sudo from the API so mailboxes are created with vmail ownership
# even when the app runs as limristem-mail (API / panel / import job setup).
set -Eeuo pipefail

SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
if [[ -x "$SCRIPT_DIR/../limristem-mail" ]]; then
  BASE_DIR=$(cd "$SCRIPT_DIR/.." && pwd)
elif [[ -x "$SCRIPT_DIR/../../limristem-mail" ]]; then
  BASE_DIR=$(cd "$SCRIPT_DIR/../.." && pwd)
else
  BASE_DIR=$(cd "$SCRIPT_DIR/.." && pwd)
fi

# shellcheck source=/dev/null
if [[ -f "$SCRIPT_DIR/libenv.sh" ]]; then
  source "$SCRIPT_DIR/libenv.sh"
elif [[ -f "$BASE_DIR/bin/libenv.sh" ]]; then
  source "$BASE_DIR/bin/libenv.sh"
fi

for envf in \
  "$BASE_DIR/config/limristem-mail.env" \
  /etc/limristem-mail.env
do
  if [[ -f "$envf" ]]; then
    # shellcheck disable=SC1090
    set -a
    # Prefer libenv loader when available
    if declare -F limristem_mail_load_env_file >/dev/null 2>&1; then
      limristem_mail_load_env_file "$envf" || true
    else
      # shellcheck disable=SC1090
      source <(grep -E '^LIMRISTEM_MAIL_[A-Z0-9_]+=' "$envf" | sed 's/^/export /') || true
    fi
    set +a
    break
  fi
done

# The env file is an *input* to this root helper, so MAIL_HOME is untrusted: a
# poisoned value would otherwise turn "ensure-mail-home" into
# `chown vmail:vmail /etc; chmod 2770 /etc`. Refuse anything that is not a
# sufficiently deep, traversal-free path outside the system directories.
validate_mail_home() {
  local raw=$1
  local path=${raw%/}
  local depth

  [[ "$path" == /* ]] || {
    echo "MAIL_HOME must be an absolute path: $raw" >&2
    exit 2
  }
  [[ "$path" != *".."* ]] || {
    echo "MAIL_HOME must not contain '..': $raw" >&2
    exit 2
  }

  depth=$(awk -F/ '{print NF-1}' <<<"$path")
  (( depth >= 3 )) || {
    echo "Refusing to manage a top-level MAIL_HOME: $raw" >&2
    exit 2
  }

  case "$path/" in
    /etc/* | /usr/* | /bin/* | /sbin/* | /lib/* | /lib64/* | /boot/* | /root/* \
      | /proc/* | /sys/* | /dev/* | /run/* | /var/lib/* | /var/log/* | /var/spool/postfix/*)
      echo "Refusing to manage MAIL_HOME inside a system path: $raw" >&2
      exit 2
      ;;
  esac

  if [[ -n "${BASE_DIR:-}" && ("$path" == "$BASE_DIR" || "$path" == "$BASE_DIR"/*) ]]; then
    echo "Refusing to manage MAIL_HOME inside the package directory: $raw" >&2
    exit 2
  fi
}

MAIL_HOME=${LIMRISTEM_MAIL_MAIL_HOME:-/var/mail/vhosts}
validate_mail_home "$MAIL_HOME"
MAIL_HOME=${MAIL_HOME%/}
VMAIL_UID=${LIMRISTEM_MAIL_VMAIL_UID:-150}
VMAIL_GID=${LIMRISTEM_MAIL_VMAIL_GID:-150}
if id vmail >/dev/null 2>&1; then
  VMAIL_UID=$(id -u vmail)
  VMAIL_GID=$(id -g vmail)
fi

usage() {
  cat <<'EOF'
Usage: manage-mailbox-fs.sh <command> [args]

Commands:
  ensure-maildir <domain> <local_part>   Create Maildir++ tree owned by vmail
  ensure-mail-home                       Ensure MAIL_HOME permissions for API writes
EOF
}

is_safe_label() {
  local value=$1
  [[ -n "$value" && ${#value} -le 255 && "$value" =~ ^[A-Za-z0-9]([A-Za-z0-9._-]*[A-Za-z0-9])?$ ]]
}

ensure_mail_home() {
  mkdir -p "$MAIL_HOME"
  # setgid + group-writable so limristem-mail (member of vmail) can create trees,
  # then chown to vmail when CAP_CHOWN or root is available.
  chown vmail:vmail "$MAIL_HOME" 2>/dev/null || chown "${VMAIL_UID}:${VMAIL_GID}" "$MAIL_HOME"
  chmod 2770 "$MAIL_HOME"
  if id limristem-mail >/dev/null 2>&1; then
    usermod -a -G vmail limristem-mail 2>/dev/null || true
  fi
}

ensure_maildir() {
  local domain=$1
  local local_part=$2
  local domain_dir mailbox special sub

  if ! is_safe_label "$domain"; then
    echo "Invalid domain label: $domain" >&2
    exit 2
  fi
  # Path-safe local part (no separators / traversal). Full RFC validation is done by the API.
  if [[ -z "$local_part" || ${#local_part} -gt 64 ]]; then
    echo "Invalid local part: $local_part" >&2
    exit 2
  fi
  if [[ "$local_part" == *"/"* || "$local_part" == *"\\"* || "$local_part" == *".."* || "$local_part" == *..* ]]; then
    echo "Invalid local part path component: $local_part" >&2
    exit 2
  fi
  if [[ "$domain" == *..* || "$domain" == *"/"* ]]; then
    echo "Invalid domain path component" >&2
    exit 2
  fi

  ensure_mail_home
  domain_dir="$MAIL_HOME/$domain"
  mailbox="$domain_dir/$local_part"
  mkdir -p "$mailbox"/{cur,new,tmp}
  for special in Sent Drafts Junk Trash Archive; do
    mkdir -p "$mailbox/.${special}"/{cur,new,tmp}
  done
  mkdir -p "$mailbox/sieve"
  if [[ ! -f "$mailbox/subscriptions" ]]; then
    printf '%s\n' Archive Drafts Junk Sent Trash | sort > "$mailbox/subscriptions"
  fi
  chown -R "${VMAIL_UID}:${VMAIL_GID}" "$domain_dir"
  chmod 2770 "$domain_dir"
  chmod 700 "$mailbox"
  find "$mailbox" -mindepth 1 -type d -exec chmod 700 {} +
  chmod 600 "$mailbox/subscriptions" 2>/dev/null || true
  # sieve dir stays private
  chmod 700 "$mailbox/sieve" 2>/dev/null || true
  printf 'ok %s\n' "$mailbox"
}

cmd=${1:-}
shift || true

case "$cmd" in
  ensure-maildir)
    [[ $# -ge 2 ]] || { echo "Usage: manage-mailbox-fs.sh ensure-maildir <domain> <local_part>" >&2; exit 2; }
    ensure_maildir "$1" "$2"
    ;;
  ensure-mail-home)
    ensure_mail_home
    echo "ok $MAIL_HOME"
    ;;
  -h|--help|help|"")
    usage
    exit 0
    ;;
  *)
    echo "Unknown command: $cmd" >&2
    usage >&2
    exit 2
    ;;
esac
