#!/bin/bash

# =============================================================================
# Скрипт для добавления DNSBL доменов в ispmanager из списка в текстовом файле
# =============================================================================
# Использование:
#   1. Создайте файл dnsbl_list.txt с доменами DNSBL (по одному на строку)
#   2. Запустите скрипт: ./add_dnsbl.sh
#   3. Скрипт добавит все домены из списка в ispmanager
# =============================================================================

# Имя файла со списком DNSBL доменов (по умолчанию)
DNSBL_FILE="dnsbl_list.txt"

# Путь к mgrctl
MGRCTL="/usr/local/mgr5/sbin/mgrctl"

# =============================================================================
# Проверка зависимостей
# =============================================================================

# Проверяем наличие mgrctl
if ! command -v "$MGRCTL" &>/dev/null; then
    echo "Ошибка: mgrctl не найден. Проверьте установку ispmanager."
    echo "Ожидаемый путь: $MGRCTL"
    exit 1
fi

# =============================================================================
# Функции
# =============================================================================

# Функция для валидации доменного имени
validate_domain() {
    local domain="$1"
    
    # Проверка на пустоту
    if [[ -z "$domain" ]]; then
        return 1
    fi
    
    # Максимальная длина домена (253 символа по RFC 1035)
    if [[ ${#domain} -gt 253 ]]; then
        return 1
    fi
    
    # Максимальная длина одной части домена (63 символа по RFC 1035)
    local IFS='.'
    local -a parts
    read -ra parts <<< "$domain"
    
    for part in "${parts[@]}"; do
        if [[ ${#part} -gt 63 ]] || [[ ${#part} -lt 1 ]]; then
            return 1
        fi
        # Каждая часть должна содержать только буквы, цифры и дефисы
        # Не может начинаться или заканчиваться дефисом
        if [[ ! "$part" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$ ]]; then
            return 1
        fi
    done
    
    # Домен должен иметь минимум 2 части (например, example.com)
    if [[ ${#parts[@]} -lt 2 ]]; then
        return 1
    fi
    
    # Последняя часть (TLD) должна быть минимум 2 символа и содержать только буквы
    local tld="${parts[-1]}"
    if [[ ${#tld} -lt 2 ]] || [[ ! "$tld" =~ ^[a-zA-Z]+$ ]]; then
        return 1
    fi
    
    # Проверка полного формата домена
    if [[ ! "$domain" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}$ ]]; then
        return 1
    fi
    
    return 0
}

# Функция для получения списка существующих DNSBL доменов
get_existing_dnsbl() {
    $MGRCTL -m ispmgr emaildnsbl 2>/dev/null | grep -oP 'name=\K[^\s]+' || true
}

# Функция для проверки существования DNSBL домена
dnsbl_exists() {
    local domain="$1"
    local existing
    existing=$(get_existing_dnsbl)
    if echo "$existing" | grep -qFx "$domain"; then
        return 0  # Домен существует
    else
        return 1  # Домен не существует
    fi
}

# Функция для добавления DNSBL домена
add_dnsbl() {
    local domain="$1"
    local result
    result=$($MGRCTL -m ispmgr emaildnsbl.edit name="$domain" sok=ok 2>&1)
    echo "$result"
}

# Функция для удаления DNSBL домена
delete_dnsbl() {
    local domain="$1"
    local result
    result=$($MGRCTL -m ispmgr emaildnsbl.delete elid="$domain" 2>&1)
    echo "$result"
}

# Функция для показа справки
show_help() {
    echo "Использование: $0 [опции]"
    echo ""
    echo "Опции:"
    echo "  -f, --file <путь>   Путь к файлу со списком DNSBL доменов"
    echo "                      (по умолчанию: dnsbl_list.txt)"
    echo "  -c, --check         Проверить список без внесения изменений"
    echo "  -d, --delete        Удалить домены из списка вместо добавления"
    echo "  -l, --list          Показать текущий список DNSBL доменов в ispmanager"
    echo "  -h, --help          Показать эту справку"
    echo ""
    echo "Примеры:"
    echo "  $0                              # Добавить домены из dnsbl_list.txt"
    echo "  $0 -f my_dnsbl.txt              # Добавить домены из my_dnsbl.txt"
    echo "  $0 -f /path/to/list.txt -c      # Проверить домены из указанного файла"
    echo "  $0 -d                           # Удалить домены из dnsbl_list.txt"
}

# Функция для показа текущего списка DNSBL
show_list() {
    echo "Текущий список DNSBL доменов в ispmanager:"
    echo "=========================================="
    local existing
    existing=$(get_existing_dnsbl)
    if [[ -z "$existing" ]]; then
        echo "(список пуст)"
    else
        echo "$existing" | while read -r domain; do
            echo "  - $domain"
        done
    fi
}

# =============================================================================
# Обработка аргументов командной строки
# =============================================================================

MODE="add"  # Режим по умолчанию: добавление
FILE_SPECIFIED=false  # Флаг: был ли указан файл через -f

while [[ $# -gt 0 ]]; do
    case $1 in
        -f|--file)
            if [[ -z "${2:-}" ]]; then
                echo "Ошибка: Не указан путь к файлу для опции $1"
                exit 1
            fi
            DNSBL_FILE="$2"
            FILE_SPECIFIED=true
            shift 2
            ;;
        -h|--help)
            show_help
            exit 0
            ;;
        -l|--list)
            show_list
            exit 0
            ;;
        -d|--delete)
            MODE="delete"
            shift
            ;;
        -c|--check)
            MODE="check"
            shift
            ;;
        -*)
            echo "Ошибка: Неизвестная опция: $1"
            show_help
            exit 1
            ;;
        *)
            # Позиционный аргумент - можно использовать как путь к файлу
            if [[ "$FILE_SPECIFIED" == false ]]; then
                DNSBL_FILE="$1"
                FILE_SPECIFIED=true
            else
                echo "Ошибка: Неожиданный аргумент: $1"
                show_help
                exit 1
            fi
            shift
            ;;
    esac
done

# Проверяем наличие файла со списком DNSBL доменов
if [[ ! -f "$DNSBL_FILE" ]]; then
    echo "Ошибка: Файл '$DNSBL_FILE' не найден."
    echo ""
    echo "Создайте файл со списком DNSBL доменов или укажите путь через -f."
    echo "Пример содержимого файла:"
    echo "  zen.spamhaus.org"
    echo "  bl.spamcop.net"
    echo "  dnsbl.sorbs.net"
    exit 1
fi

# =============================================================================
# Загрузка и валидация списка DNSBL доменов из файла
# =============================================================================

# Загружаем домены из файла, пропуская пустые строки и комментарии
mapfile -t DNSBL_RAW < "$DNSBL_FILE"
DNSBL_LIST=()
INVALID_LINES=()

for LINE in "${DNSBL_RAW[@]}"; do
    # Удаляем лишние символы и пробелы
    LINE=$(echo "$LINE" | tr -d '\r' | xargs)
    
    # Пропускаем пустые строки и комментарии
    if [[ -z "$LINE" ]] || [[ "$LINE" =~ ^[[:space:]]*# ]]; then
        continue
    fi
    
    # Проверяем валидность доменного имени
    if validate_domain "$LINE"; then
        DNSBL_LIST+=("$LINE")
    else
        INVALID_LINES+=("$LINE")
    fi
done

# Показываем невалидные строки, если есть
if (( ${#INVALID_LINES[@]} > 0 )); then
    echo "============================================"
    echo "  Предупреждение: найдены некорректные строки"
    echo "============================================"
    echo ""
    echo "Следующие строки не являются валидными доменными именами и будут пропущены:"
    for line in "${INVALID_LINES[@]}"; do
        echo "  ✗ $line"
    done
    echo ""
fi

# Проверяем, есть ли хоть один валидный домен
if (( ${#DNSBL_LIST[@]} == 0 )); then
    echo "Ошибка: В файле '$DNSBL_FILE' не найдено ни одного корректного DNSBL домена."
    echo ""
    echo "Требования к доменному имени:"
    echo "  - Содержит только буквы, цифры, точки и дефисы"
    echo "  - Минимум 2 части (например: example.com)"
    echo "  - TLD (последняя часть) минимум 2 буквы"
    echo "  - Общая длина не более 253 символов"
    echo "  - Каждая часть не более 63 символов"
    exit 1
fi

# =============================================================================
# Основная логика
# =============================================================================

echo "============================================"
echo "  Скрипт добавления DNSBL доменов"
echo "============================================"
echo ""
echo "Режим: $MODE"
echo "Файл: $DNSBL_FILE"
echo "Валидных доменов: ${#DNSBL_LIST[@]}"
if (( ${#INVALID_LINES[@]} > 0 )); then
    echo "Пропущено некорректных строк: ${#INVALID_LINES[@]}"
fi
echo ""

# Показываем список доменов для обработки
echo "Домены для обработки:"
echo "---------------------"
for domain in "${DNSBL_LIST[@]}"; do
    echo "  - $domain"
done
echo ""

# Получаем список существующих DNSBL доменов
EXISTING_DNSBL=$(get_existing_dnsbl)
if [[ -n "$EXISTING_DNSBL" ]]; then
    EXISTING_COUNT=$(echo "$EXISTING_DNSBL" | wc -l)
    echo "Текущее количество DNSBL доменов в ispmanager: $EXISTING_COUNT"
else
    echo "Текущее количество DNSBL доменов в ispmanager: 0"
fi

# Режим проверки
if [[ "$MODE" == "check" ]]; then
    echo ""
    echo "============================================"
    echo "  Режим проверки (без изменений)"
    echo "============================================"
    
    NEW_COUNT=0
    EXISTS_COUNT=0
    
    for domain in "${DNSBL_LIST[@]}"; do
        if dnsbl_exists "$domain"; then
            echo "  [УЖЕ ЕСТЬ] $domain"
            ((EXISTS_COUNT++))
        else
            echo "  [НОВЫЙ]    $domain"
            ((NEW_COUNT++))
        fi
    done
    
    echo ""
    echo "Результат проверки:"
    echo "  Новых доменов: $NEW_COUNT"
    echo "  Уже существует: $EXISTS_COUNT"
    exit 0
fi

# Подтверждение перед выполнением
read -p "Продолжить? (y/n) [default: y]: " CONFIRM
CONFIRM=${CONFIRM:-y}
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
    echo "Операция отменена."
    exit 0
fi

echo ""
echo "============================================"
echo "  Выполнение операции"
echo "============================================"

# Счётчики
SUCCESS_COUNT=0
SKIP_COUNT=0
ERROR_COUNT=0

# Обработка каждого домена
for domain in "${DNSBL_LIST[@]}"; do
    echo ""
    echo "Обработка: $domain"
    echo "----------------------------------------"
    
    if [[ "$MODE" == "add" ]]; then
        # Проверяем, существует ли уже домен
        if dnsbl_exists "$domain"; then
            echo "  ⚠ Домен уже существует в списке DNSBL"
            ((SKIP_COUNT++))
            continue
        fi
        
        # Добавляем домен
        echo "  Добавление DNSBL домена..."
        RESULT=$(add_dnsbl "$domain")
        
        # Проверяем результат
        if echo "$RESULT" | grep -qi "error\|Error\|ERROR"; then
            echo "  ✗ Ошибка: $RESULT"
            ((ERROR_COUNT++))
        else
            echo "  ✓ Успешно добавлен"
            ((SUCCESS_COUNT++))
        fi
        
    elif [[ "$MODE" == "delete" ]]; then
        # Проверяем, существует ли домен
        if ! dnsbl_exists "$domain"; then
            echo "  ⚠ Домен не найден в списке DNSBL"
            ((SKIP_COUNT++))
            continue
        fi
        
        # Удаляем домен
        echo "  Удаление DNSBL домена..."
        RESULT=$(delete_dnsbl "$domain")
        
        # Проверяем результат
        if echo "$RESULT" | grep -qi "error\|Error\|ERROR"; then
            echo "  ✗ Ошибка: $RESULT"
            ((ERROR_COUNT++))
        else
            echo "  ✓ Успешно удалён"
            ((SUCCESS_COUNT++))
        fi
    fi
done

# =============================================================================
# Итоговый отчёт
# =============================================================================

echo ""
echo "============================================"
echo "  Итоговый отчёт"
echo "============================================"
echo ""
echo "Режим: $MODE"
echo "Всего обработано: ${#DNSBL_LIST[@]}"
echo ""

if [[ "$MODE" == "add" ]]; then
    echo "  ✓ Добавлено:   $SUCCESS_COUNT"
    echo "  ⚠ Пропущено:   $SKIP_COUNT"
    echo "  ✗ Ошибок:      $ERROR_COUNT"
elif [[ "$MODE" == "delete" ]]; then
    echo "  ✓ Удалено:     $SUCCESS_COUNT"
    echo "  ⚠ Пропущено:   $SKIP_COUNT"
    echo "  ✗ Ошибок:      $ERROR_COUNT"
fi

echo ""
echo "============================================"
echo "  Операция завершена"
echo "============================================"

# Показываем обновлённый список
echo ""
echo "Текущий список DNSBL доменов:"
show_list

exit 0