Ctrl K
ComunidadGuías…

install.sh

Rama dev · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

CONTAINER_PROJECT_NAME=billionmail
PGSQL_CONTAINER_NAME="${CONTAINER_PROJECT_NAME}-pgsql-billionmail-1"
DOVECOT_CONTAINER_NAME="${CONTAINER_PROJECT_NAME}-dovecot-billionmail-1"
POSTFIX_CONTAINER_NAME="${CONTAINER_PROJECT_NAME}-postfix-billionmail-1"
RSPAMD_CONTAINER_NAME="${CONTAINER_PROJECT_NAME}-rspamd-billionmail-1"
create_time=$(date +%s)
DBNAME=billionmail
DBUSER=billionmail
SMTP_PORT=25
SMTPS_PORT=465
SUBMISSION_PORT=587
IMAP_PORT=143
IMAPS_PORT=993
POP_PORT=110
POPS_PORT=995
REDIS_PORT=127.0.0.1:26379
SQL_PORT=127.0.0.1:25432
HTTP_PORT=80
HTTPS_PORT=443
SafePath=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 8)
REDISPASS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 32)
ADMIN_USERNAME=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 8)
ADMIN_PASSWORD=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 8)
time=$(date +%Y_%m_%d_%H_%M_%S)

PWD_d=`pwd`
download_Url=https://node.aapanel.com
mirror=''
Default_Download_Url=""

CPU_architecture=$(uname -m)

# List of supported architectures
SUPPORTED_ARCHS=("x86_64" "aarch64")

# Check whether the current architecture is supported
if [[ ! " ${SUPPORTED_ARCHS[@]} " =~ " ${CPU_architecture} " ]]; then
    echo -e "\033[31mSorry, not support the ${CPU_architecture} architecture for install. \nPlease use the x86_64, aarch64 server architecture. \033[0m"
    exit 1
fi

is64bit=$(getconf LONG_BIT)
if [ "${is64bit}" != '64' ];then
    echo -e "\033[31m Sorry, BillionMail does not support 32-bit systems \033[0m"
    exit 1
fi


if [ $(whoami) != "root" ];then
    echo -e "Non-root install, please try the following solutions: \n   1.Please switch to root user install \n   2.Try executing the following install commands: \n     sudo bash $0 $@"
    exit 1
fi

while [ ${#} -gt 0 ]; do
    case $1 in
        -h|--help)
            echo "Usage:  [options]"
            echo "Options:"
            echo "  -d, --domain          Set Mail Server domain. eg: example.com"
            echo "  -t, --TZ              Set Time Zone. eg: CST"
            echo "   Time Zone See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for a list of timezones"
            echo "   Use a column named "TZ identifier" + note the column named "Notes""
            echo "eg: bash install.sh --domain example.com --TZ CST"
            exit 0
            ;;
        -d|--domain)
            BILLIONMAIL_HOSTNAME=$2
            shift 1
            ;;
        -t|--TZ)
            BILLIONMAIL_TIME_ZONE=$2
            shift 1
            ;;
    esac
    shift 1
done

if [ -f "billionmail.conf" ]; then
read -r -p "Check that the configuration file exists, will you continue to overwrite the file?? [y/N] " gogo
case $gogo in
    [Yy][eE][sS]|[Yy])
    if [ ! -d "./backup/" ]; then
        mkdir ./backup
    fi
        mv billionmail.conf ./backup/billionmail.conf_${time}
    echo "Backup: billionmail.conf --> ./backup/billionmail.conf_${time}"
    if [ -f ".env" ]; then
        mv .env env_${time}
        echo "Backup: .env --> ./backup/env_${time}"
    fi
    ;;
    *)
    exit 1
    ;;
esac
fi

# while [ -z "${BILLIONMAIL_HOSTNAME}" ]; do
# echo "Press Enter to confirm the detected value '[value]', or enter a custom value."
# echo -e ""
#     echo -e "Mail Server hostname (FQDN), \e[0;33mAs: example.com\e[0m"
#     echo -e ""
#     read -p "Please enter the Mail Server hostname (FQDN: e.g. example.com): " -e BILLIONMAIL_HOSTNAME
#     #if [[ ! "${BILLIONMAIL_HOSTNAME}" =~ ^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9](\.[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])*$ ]]; then
#     if [[ ! "${BILLIONMAIL_HOSTNAME}" =~ ^([a-zA-Z0-9]([a-zA-Z0-9-]{0,62}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$ ]]; then
#         echo -e "\e[31m(${BILLIONMAIL_HOSTNAME}) is not a FQDN!\e[0m"
#         echo "Please change it to a FQDN"
#         exit 1
#     elif [[ "${BILLIONMAIL_HOSTNAME: -1}" == "." ]]; then
#         echo "(${BILLIONMAIL_HOSTNAME}) is ending with a dot. This is not a valid FQDN!"
#         exit 1

#     fi
# done

if [ -z "${BILLIONMAIL_HOSTNAME}" ]; then
    BILLIONMAIL_HOSTNAME="example.com"
fi

# Count number of dots in the domain
DOT_COUNT=$(echo "${BILLIONMAIL_HOSTNAME}" | tr -cd '.' | wc -c)

# If only one dot, prepend "mail."
if [ "${DOT_COUNT}" -eq 1 ]; then
    ADD_MAIL_BILLIONMAIL_HOSTNAME="mail.${BILLIONMAIL_HOSTNAME}"
    echo "Postfix myhostname configuration use: ${ADD_MAIL_BILLIONMAIL_HOSTNAME}"
fi

# Ensure ADD_MAIL_BILLIONMAIL_HOSTNAME is always set (fallback to original if empty)
if [ -z "${ADD_MAIL_BILLIONMAIL_HOSTNAME}" ]; then
    ADD_MAIL_BILLIONMAIL_HOSTNAME="${BILLIONMAIL_HOSTNAME}"
    echo "Postfix myhostname configuration use: ${ADD_MAIL_BILLIONMAIL_HOSTNAME}"
fi

if [ -a /etc/timezone ]; then
    SYSTEM_TIME_ZONE=$(cat /etc/timezone)
elif [ -a /etc/localtime ]; then
    SYSTEM_TIME_ZONE=$(readlink /etc/localtime|sed -n 's|^.*zoneinfo/||p')
fi

# while [ -z "${BILLIONMAIL_TIME_ZONE}" ]; do
#     echo -e ""
#     echo -e "See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for a list of timezones"
#     echo -e "Use a column named "TZ identifier" + note the column named "Notes""
#     echo -e "Please enter your time zone"
#     echo -e ""
#     if [ -z "${SYSTEM_TIME_ZONE}" ]; then
#         read -p "Timezone: " -e BILLIONMAIL_TIME_ZONE
#     else
#         read -p "Timezone [${SYSTEM_TIME_ZONE}]: " -e BILLIONMAIL_TIME_ZONE
#         [ -z "${BILLIONMAIL_TIME_ZONE}" ] && BILLIONMAIL_TIME_ZONE=${SYSTEM_TIME_ZONE}
#     fi
# done

BILLIONMAIL_TIME_ZONE=${SYSTEM_TIME_ZONE}
if [ -z "${BILLIONMAIL_TIME_ZONE}" ]; then
    BILLIONMAIL_TIME_ZONE="America/New_York"
fi

DBPASS_file=DBPASS_file.pl
if [ ! -s "${DBPASS_file}" ]; then
    DBPASS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 32)
    echo "${DBPASS}" > ${DBPASS_file}
    chmod 600 ${DBPASS_file}
else
    DBPASS=$(cat ${DBPASS_file})
fi


GetSysInfo(){
    if [ -s "/etc/redhat-release" ];then
        SYS_VERSION=$(cat /etc/redhat-release)
    elif [ -s "/etc/issue" ]; then
        SYS_VERSION=$(cat /etc/issue)
    fi
    SYS_INFO=$(uname -a)
    SYS_BIT=$(getconf LONG_BIT)
    MEM_TOTAL=$(free -m|grep Mem|awk '{print $2}')
    CPU_INFO=$(getconf _NPROCESSORS_ONLN)

    echo -e ${SYS_VERSION}
    echo -e Bit:${SYS_BIT} Mem:${MEM_TOTAL}M Core:${CPU_INFO}
    echo -e ${SYS_INFO}
    echo -e "Please screenshot the above error message and post to the https://github.com/aaPanel/BillionMail/issues for help"

}


Red_Error(){
    echo '=================================================';
    printf '\033[1;31;40m%b\033[0m\n' "$@";
    GetSysInfo
    exit 1;
}



PORT(){

    if Command_Exists ss ; then
        command_port="ss"
        
    elif Command_Exists netstat ; then
        command_port="netstat"
    else
        echo -e "Command does not exist and cannot check whether the port is used"
        command_port=""
    fi

    if [[ ! -z $command_port ]]; then
        
        
        #check_command=$($command_port -ltnp | grep -E ':(25|465|587|110|143|993|995)\s')
        check_command=$($command_port -ltnp | grep -E ":(${SMTP_PORT}|${SMTPS_PORT}|${SUBMISSION_PORT}|${POP_PORT}|${IMAP_PORT}|${IMAPS_PORT}|${POPS_PORT})\s")
        if [[ ! -z "$check_command" ]]; then
            echo "Checking the port is used:"
            echo "$check_command"|grep -v "docker-proxy"
            echo -e "\033[1;31m BillionMail need use port ${SMTP_PORT}|${SMTPS_PORT}|${SUBMISSION_PORT}|${POP_PORT}|${IMAP_PORT}|${IMAPS_PORT}|${POPS_PORT}.\033[0m There are already services ports in the system. "
            # exit 1
        fi
    fi
}

Check_Port(){
    # if ! Command_Exists docker; then
    #     PORT
    # else
    #     check=$(docker ps |grep -wE "${POSTFIX_CONTAINER_NAME}|${DOVECOT_CONTAINER_NAME}")
    #     if [[ -z "$check" ]]; then
    #         PORT
    #     fi
    # fi
    PORT
}


LXC_install_tips (){
    # Check if it is in the lxc container
    System_Info=$(hostnamectl)
    check_container=$(echo "$System_Info" |grep "Chassis"|awk -F":" '{print $2}')
    #echo $check_container
    if [[ "$check_container" =~ "container" ]];then
        echo -e "\033[33mInstalling in an LXC container,May not install properly. \nDocker may not be able to correctly obtain the number of CPU cores, \nwhich may cause the system to crash and cause high load when nginx is running. \nRecommended use VPS or physical machine for install.\033[0m"
        echo -e ""
        echo -e "\033[33mMust be turned on \"Unprivileged container\", \"nesting\". Otherwise the container cannot be started.\033[0m"
        echo "Please confirm whether continue install?"
        while [ "$lxc" != 'y' ] && [ "$lxc" != 'n' ]; do
            read -p "Please confirm whether in LXC container continue install? (y/n): " lxc;
        done

        if [ "$lxc" == 'n' ];then
            echo "Install canceled."
            exit;
        fi

        LXC_install="yes"
    fi
}


Get_Pack_Manager(){
	if [ -f "/usr/bin/yum" ] && [ -d "/etc/yum.repos.d" ]; then
		PM="yum"
	elif [ -f "/usr/bin/apt-get" ] && [ -f "/usr/bin/dpkg" ]; then
		PM="apt-get"		
	fi
}


Install_RPM_Pack(){
	yumPacks="wget curl tar gzip git firewalld ca-certificates";
	yum install -y ${yumPacks}

	for yumPack in ${yumPacks}
	do
		rpmPack=$(rpm -q ${yumPack})
		packCheck=$(echo ${rpmPack}|grep not)
		if [ "${packCheck}" ]; then
			yum install ${yumPack} -y
		fi
	done

    setenforce 0
    sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
}

Install_Deb_Pack(){
    debPacks="wget curl tar gzip git lsb-release ufw ca-certificates";
	apt-get update -y
	DEBIAN_FRONTEND=noninteractive apt-get install -y $debPacks --allow-downgrades --allow-remove-essential --allow-change-held-packages

	for debPack in ${debPacks}
	do
		packCheck=$(dpkg -l ${debPack})
		if [ "$?" -ne "0" ] ;then
			apt-get install -y $debPack
		fi
	done
}

Command_Exists() {
    command -v "$@" >/dev/null 2>&1
}

Docker_Download_Url_Check() {
    echo -e "Selecting download docker address source, please wait..."
    ser_names=(download.docker.com mirrors.ustc.edu.cn/docker-ce mirrors.tuna.tsinghua.edu.cn/docker-ce mirrors.aliyun.com/docker-ce mirror.azure.cn/docker-ce)
    tmp_file1=/dev/shm/net_test1.pl
	tmp_file2=/dev/shm/net_test2.pl
    [ -f "${tmp_file1}" ] && rm -f ${tmp_file1}
    [ -f "${tmp_file2}" ] && rm -f ${tmp_file2}
    touch $tmp_file1
    touch $tmp_file2

    for ser_name in ${ser_names[@]};
    do
        NODE_CHECK=$(curl -k -s 2>/dev/null --connect-timeout 5 -w "%{http_code} %{time_total}" https://${ser_name} -o c${ser_name}.txt|xargs)
        rm -rf c${ser_name}.txt
        NODE_STATUS=$(echo ${NODE_CHECK}|awk '{print $1}')
        TIME_TOTAL=$(echo ${NODE_CHECK}|awk '{print $2 * 1000 - 500 }'|cut -d '.' -f 1)
        if [ "${NODE_STATUS}" == "200" ] || [ "${NODE_STATUS}" == "301" ] || [ "${NODE_STATUS}" == "403" ];then
            if [ $TIME_TOTAL -lt 100 ]; then
                echo "$ser_name" >> $tmp_file1
            elif [ $TIME_TOTAL -gt 1500 ] && [ $TIME_TOTAL -lt 2500 ]; then
                echo "$ser_name" >> $tmp_file2
            fi
        fi
    done
    Docker_NODE_URL=$(cat $tmp_file1|head -n 1|awk '{print $1}')
        if [ -z "$Docker_NODE_URL" ];then
            Docker_NODE_URL=$(cat $tmp_file2|head -n 1|awk '{print $1}')
        fi

    rm -f $tmp_file1
    rm -f $tmp_file2
    mirror="$Docker_NODE_URL"
    echo $mirror
    case "$mirror" in
    mirrors.aliyun.com/docker-ce)
        Default_Download_Url="https://mirrors.aliyun.com/docker-ce"
        mirror="Aliyun"
        ;;
    mirror.azure.cn/docker-ce)
        Default_Download_Url="https://mirror.azure.cn/docker-ce"
        mirror="AzureChinaCloud"
        ;;
    mirrors.ustc.edu.cn/docker-ce)
        Default_Download_Url="https://mirrors.ustc.edu.cn/docker-ce"
        mirror="USTC"
        ;;
    mirrors.tuna.tsinghua.edu.cn/docker-ce)
        Default_Download_Url="https://mirrors.tuna.tsinghua.edu.cn/docker-ce"
        mirror="tsinghua"
        ;;
    *)
        Default_Download_Url="https://download.docker.com"
        mirror=""
        ;;
    esac

    DEFAULT_REPO_FILE="docker-ce.repo"

    if [ -z "$REPO_FILE" ]; then
        REPO_FILE="$DEFAULT_REPO_FILE"
    fi
}

Get_Distribution() {
    lsb_dist=""
    lsb_name=""

    if [ -r /etc/os-release ]; then
        lsb_dist="$(. /etc/os-release && echo "$ID")"
        lsb_name="$(. /etc/os-release && echo "$NAME")"
    fi
    echo "$lsb_dist $lsb_name"
}


Bored_waiting(){
    w_time="$wait_time"
    msg="$wait_msg"
    progress="."
    for ((i=0; i<${w_time}; i++))
    do
        printf "$msg %-10s %d\r" "$progress" "$((i+1))"
        sleep 1

        if [ "$progress" == ".........." ]; then
            progress="."
        else
            progress+="."
        fi
    done
    printf "$msg %-10s %d\r" ".........." "$w_time"
    #echo ""
}

Docker_Start() {
    if Command_Exists docker || [ -f /lib/systemd/system/docker.service ]; then
        if Command_Exists systemctl; then
            # systemctl mask getty@tty1.service
            grep docker /etc/group >/dev/null 2>&1 || groupadd docker
            systemctl enable docker
            systemctl reset-failed docker.service
            systemctl start docker.service
            if [ "$?" != "0" ];then
                systemctl reset-failed docker.service
                systemctl restart docker.service
                if [ "$?" != "0" ];then
                    docker_status=$(systemctl status docker.service)
                    echo "$docker_status"
                    if [ -f /etc/docker/daemon.json ]; then
                        echo "/etc/docker/daemon.json file content:"
                        cat /etc/docker/daemon.json
                        echo -e "\033[33mRecommended check the above /etc/docker/daemon.json Are the file contents correct?\033[0m"
                    fi
                    # Wait for 100 seconds of animation
                    echo -e "\033[31m start docker service failed, maybe too fast to start\033[0m"
                    wait_msg="waiting 100 seconds to start docker service"
                    wait_time="100"
                    Bored_waiting
                    systemctl reset-failed docker.service
                    systemctl restart docker.service
                    if [ "$?" != "0" ];then
                        docker_status=$(systemctl status docker.service)
                        echo "$docker_status"
                        Red_Error "docker start failed" "Please try again later execute the restart docker command: systemctl restart docker.service (no content returns normal)" "Finally, re-execute install BillionMail"
                    fi
                fi
            fi
        else
            chkconfig --add docker
            chkconfig --level 2345 docker on
            service docker start
            if [ "$?" != "0" ];then
                service docker.service status
                cat /etc/docker/daemon.json
                Red_Error "docker start failed"
            fi
        fi
    else
        
        Red_Error "Docker is not installed"
    
    
    
    fi
}


Is_Darwin() {
    case "$(uname -s)" in
    *darwin*) true ;;
    *Darwin*) true ;;
    *) false ;;
    esac
}

Check_Forked() {
    if Command_Exists lsb_release; then
        set +e
        lsb_release -a -u >/dev/null 2>&1
        lsb_release_exit_code=$?

        if [ "$lsb_release_exit_code" = "0" ]; then
            cat <<-EOF
You're using '$lsb_dist' version '$dist_version'.
EOF
            lsb_dist=$(lsb_release -a -u 2>&1 | tr '[:upper:]' '[:lower:]' | grep -E 'id' | cut -d ':' -f 2 | tr -d '[:space:]')
            dist_version=$(lsb_release -a -u 2>&1 | tr '[:upper:]' '[:lower:]' | grep -E 'codename' | cut -d ':' -f 2 | tr -d '[:space:]')
            cat <<-EOF
Upstream release is '$lsb_dist' version '$dist_version'.
EOF
        else
            if [ -r /etc/debian_version ] && [ "$lsb_dist" != "ubuntu" ] && [ "$lsb_dist" != "raspbian" ]; then
                if [ "$lsb_dist" = "osmc" ]; then
                    lsb_dist=raspbian
                else
                    lsb_dist=debian
                fi
                dist_version="$(sed 's/\/.*//' /etc/debian_version | sed 's/\..*//')"
                case "$dist_version" in
                12)
	                dist_version="bookworm"
                    ;;
                11)
                    dist_version="bullseye"
                    ;;
                10)
                    dist_version="buster"
                    ;;
                9)
                    dist_version="stretch"
                    ;;
                8)
                    dist_version="jessie"
                    ;;
                esac
            fi
        fi
    fi
}


Docker_Check(){

    # Default value is: 0 Not installed
    is_docker="0"
    docker_version="docker version"
    if Command_Exists $docker_version ; then
        is_docker="1"
    fi
    echo "docker command: $is_docker"

}

create_docker_yum_repo() {
    cat <<EOF >/etc/yum.repos.d/docker-ce.repo
[docker-ce-stable]
name=Docker CE Stable - \$basearch
baseurl=https://download.docker.com/linux/centos/\$releasever/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg

EOF
}


Docker_Install() {
    lsb_dist=$(Get_Distribution|awk -F " " '{print $1}')
    lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')"

    case "$lsb_dist" in
    ubuntu)
        if Command_Exists lsb_release; then
            dist_version="$(lsb_release --codename | cut -f2)"
        fi
        if [ -z "$dist_version" ] && [ -r /etc/lsb-release ]; then
            dist_version="$(. /etc/lsb-release && echo "$DISTRIB_CODENAME")"
        fi
        ;;
    debian | raspbian)
        dist_version="$(sed 's/\/.*//' /etc/debian_version | sed 's/\..*//')"
        case "$dist_version" in
        12)
            dist_version="bookworm"
            ;;
        11)
            dist_version="bullseye"
            ;;
        10)
            dist_version="buster"
            ;;
        9)
            dist_version="stretch"
            ;;
        8)
            dist_version="jessie"
            ;;
        esac
        ;;
    centos | rhel | sles | ol | tencentos | alinux | anolis | rocky | euleros | almalinux | opencloudos |openeuler |hce | kylin |uos | kylinsecos |amzn )
        if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then
            dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
        fi
        ;;
    *)
        if Command_Exists lsb_release; then
            dist_version="$(lsb_release --release | cut -f2)"
        fi
        if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then
            dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
        fi
        ;;
    esac

    Check_Forked

    case "$lsb_dist" in
    ubuntu | debian | raspbian)
        docker_gpg="/usr/share/keyrings/docker-archive-keyring.gpg"
        apt_repo_file="/etc/apt/sources.list.d/docker.list"
        pre_reqs="apt-transport-https ca-certificates curl wget"

        if ! command -v gpg >/dev/null; then
            pre_reqs="$pre_reqs gnupg"
        fi

        apt_repo="deb [arch=$(dpkg --print-architecture) signed-by=$docker_gpg] $Default_Download_Url/linux/$lsb_dist $dist_version stable"
        (
            DEBIAN_FRONTEND=noninteractive apt-get install -y $pre_reqs
            if [ -f $docker_gpg ] && [ -f $apt_repo_file ]; then
                rm -rf $docker_gpg
                rm -rf $apt_repo_file
            fi

            #curl -fsSL --connect-time 10 --retry 5 $Default_Download_Url/linux/$lsb_dist/gpg | gpg --dearmor --yes -o $docker_gpg
            #wget --no-check-certificate -qO - -t 5 -T 20 $Default_Download_Url/linux/$lsb_dist/gpg | gpg --dearmor --yes -o $docker_gpg
            wget -qO - -t 5 -T 10 $Default_Download_Url/linux/$lsb_dist/gpg | gpg --dearmor --yes -o $docker_gpg
            chmod a+r $docker_gpg

            echo "$apt_repo" > $apt_repo_file
            apt-get update -y
        )
        pkg_version=""

        #First check whether apt-get is used. It cannot be put into the subshell, that is, () to execute, otherwise it will not exit.
        # Check_apt_status

        (
            pkgs="$pkgs docker-ce${pkg_version%=}"
            DEBIAN_FRONTEND=noninteractive apt-get install -y $pkgs docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
        )
        ;;
    centos | fedora | rhel | ol | tencentos | alinux | anolis | rocky | almalinux | opencloudos |openeuler |hce |uos |amzn )
        pkg_version=""

        yum_repo="$Default_Download_Url/linux/$lsb_dist/$REPO_FILE"
        if [ "$lsb_dist" == "ol" ] || [ "$lsb_dist" == "tencentos" ] || [ "$lsb_dist" == "alinux" ] || [ "$lsb_dist" == "anolis" ] || [ "$lsb_dist" == "opencloudos" ] || [ "$lsb_dist" == "openeuler" ] || [ "$lsb_dist" == "hce" ] || [ "$lsb_dist" == "uos" ] || [ "$lsb_dist" == "amzn" ] ; then
            yum_repo="$Default_Download_Url/linux/centos/$REPO_FILE"
        fi
        if [ "$lsb_dist" == "rocky" ] || [ "$lsb_dist" == "almalinux" ]; then
            yum_repo="$Default_Download_Url/linux/centos/$REPO_FILE"
        fi
        if [ "$lsb_dist" = "fedora" ]; then
            pkg_manager="dnf"
            config_manager="dnf config-manager"
            enable_channel_flag="--set-enabled"
            disable_channel_flag="--set-disabled"
            pre_reqs="dnf-plugins-core"
            pkg_suffix="fc$dist_version"
        else
            pkg_manager="yum"
            config_manager="yum-config-manager"
            enable_channel_flag="--enable"
            disable_channel_flag="--disable"
            pre_reqs="yum-utils"
            pkg_suffix="el"
        fi
    
        #wget --no-check-certificate -O /etc/yum.repos.d/docker-ce.repo $yum_repo -t 5 -T 10
        wget -O /etc/yum.repos.d/docker-ce.repo $yum_repo -t 5 -T 10
        if [ $? -ne "0" ]; then
            create_docker_yum_repo
        fi
        
        if ! grep -q "docker" /etc/yum.repos.d/docker-ce.repo; then
            create_docker_yum_repo
        fi

        sed -i "s|https://download.docker.com|$Default_Download_Url|g" /etc/yum.repos.d/docker-ce.repo
        # cat /etc/yum.repos.d/docker-ce.repo
       
        lsb_name=$(Get_Distribution|awk -F " " '{print $3}')
        echo $lsb_name
        echo $lsb_dist
        #if [ "$lsb_name" = "Stream" ] || [ "$lsb_dist" = "alinux" ] || [ "$lsb_dist" = "anolis" ];then
        #if [ "$lsb_name" = "Stream" ] || [ "$lsb_dist" = "anolis" ];then
        if [ "$lsb_name" = "Stream" ]; then
            conflicting="--allowerasing"
        fi
        if [ "$lsb_name" = "rocky" ] || [ "$lsb_dist" = "euleros" ] || [ "$lsb_dist" = "almalinux" ];then
            conflicting="--allowerasing"
        fi

        if [ "$lsb_dist" = "openeuler" ];then
            openeuler_v=$(cat /etc/os-release |grep "VERSION=")
            if [[ $openeuler_v =~ "23.0" ]]; then
                
                sed -i "s|\$releasever|8|g" /etc/yum.repos.d/docker-ce.repo
                $pkg_manager makecache
                
            elif [[ $openeuler_v =~ "22.0" ]]; then
                sed -i "s|\$releasever|7|g" /etc/yum.repos.d/docker-ce.repo
                $pkg_manager makecache
            else
                if [ -f "/etc/os-release" ]; then
                    cat /etc/os-release
                fi
                echo "ERROR: not support this system yum auto install docker"
            fi
        fi

        # Amazon Linux
        if [ "$lsb_dist" = "amzn" ];then
            #amzn_v=$(. /etc/os-release && echo "$VERSION_ID")

            sed -i "s|\$releasever|8|g" /etc/yum.repos.d/docker-ce.repo
            $pkg_manager makecache
        fi

        # Huawei Cloud EulerOS 
        if [ "$lsb_dist" = "hce" ];then
            hce_v=$(. /etc/os-release && echo "$VERSION_ID")
            if [[ $hce_v =~ "2.0" ]]; then
                sed -i "s|\$releasever|8|g" /etc/yum.repos.d/docker-ce.repo
                $pkg_manager makecache
            else
                if [ -f "/etc/os-release" ]; then
                    cat /etc/os-release
                fi
                echo "ERROR: not support this system yum auto install docker"
            fi
        fi

        # OpenCloudOS 9.0
        if [ "$lsb_dist" = "opencloudos" ];then
            pkg_manager="yum"
            opencloudos_v=$(. /etc/os-release && echo "$VERSION_ID")
            if [[ $opencloudos_v =~ "9.0" ]]; then

                sed -i "s|\$releasever|8|g" /etc/yum.repos.d/docker-ce.repo
                # centos 8
                download_container_selinux="$download_Url/cloudwaf/package/container-selinux-2.224.0-1.module_el8+712+4cd1bd69.noarch.rpm"
                wget --no-check-certificate -O container-selinux-2.224.0-1.module_el8+712+4cd1bd69.noarch.rpm ${download_container_selinux} -t 5 -T 10

                install_docker="1"
                $pkg_manager makecache
                
                $pkg_manager install -y docker-ce$pkg_version docker-ce-cli docker-buildx-plugin docker-compose-plugin container-selinux-2.224.0-1.module_el8+712+4cd1bd69.noarch.rpm

                rm -f container-selinux-2.224.0-1.module_el8+712+4cd1bd69.noarch.rpm

            fi
        fi

        if [ "$lsb_dist" = "uos" ];then
            pkg_manager="yum"
            uos_v=$(. /etc/os-release && echo "$VERSION_ID")
            uos_NAME=$(. /etc/os-release && echo "$NAME")
            if [[ $uos_v =~ "20" ]] && [[ "$uos_NAME" == "UOS Server Euler" ]]; then
            # UOS Server Euler 20 Install using the default source
                if [ -f /etc/yum.repos.d/docker-ce.repo ]; then
                    rm -f /etc/yum.repos.d/docker-ce.repo
                fi
                # Define to install docker using other commands
                install_docker="1"
                $pkg_manager makecache

                $pkg_manager install -y docker* --skip-broken

            elif [[ $uos_v =~ "20" ]]; then
                sed -i "s|\$releasever|8|g" /etc/yum.repos.d/docker-ce.repo

                # Define to install docker using other commands
                install_docker="1"

                $pkg_manager makecache

                $pkg_manager install -y docker-ce$pkg_version docker-ce-cli docker-buildx-plugin docker-compose-plugin


            else
                if [ -f "/etc/os-release" ]; then
                    cat /etc/os-release
                fi
                echo "ERROR: not support this system yum auto install docker"
            fi
        fi

        if [[ "$install_docker" != "1" ]]; then
        # 1 When docker is installed using other commands
            $pkg_manager makecache

            $pkg_manager install -y docker-ce$pkg_version docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin $conflicting

        fi
        ;;

    *)
        if [ -z "$lsb_dist" ]; then
            if Is_Darwin; then
                echo
                echo "ERROR: Unsupported operating system 'macOS'"
                echo
                exit 1
            fi
        fi
        echo
        Red_Error "ERROR: not support '$lsb_dist' this system auto install docker"
        ;;
    esac

    if ! Command_Exists docker && [ ! -f /usr/bin/docker ]; then
        echo "Trying to install docker using binary package method."
        
        Binary_package_install_docker
        
    fi

    if ! Command_Exists docker ; then
        Red_Error "docker command not exists,install docker failed,please check the reason."     
    fi
}


Binary_package_install_docker(){
# Install docker in binary package
    DOCKER_VERSION="27.3.1"
    SYS_TYPE=$(uname -m)

    echo "Create docker group"
    groupadd docker

    echo "Downloading docker ${DOCKER_VERSION}.tgz file, please wait..."
    wget --no-check-certificate -O docker-${DOCKER_VERSION}.tgz ${download_Url}/src/docker-${DOCKER_VERSION}-${SYS_TYPE}.tgz -t 5 -T 10

    tmp_size=$(du -b docker-${DOCKER_VERSION}.tgz |awk '{print $1}')
    if [ $tmp_size -lt 60831072 ];then
        ls -l docker-${DOCKER_VERSION}.tgz
        Red_Error "ERROR: Failed to download, please try install again!"
    fi

    echo "Unzip the docker ${DOCKER_VERSION}.tgz file, please wait..."
    tar -xvf docker-${DOCKER_VERSION}.tgz
    \cp docker/* /usr/bin/

    # rm -rf docker
    rm -f docker-${DOCKER_VERSION}.tgz

    wget --no-check-certificate -O /usr/bin/docker-compose ${download_Url}/src/docker-compose-linux-${SYS_TYPE} -t 5 -T 20
    chmod +x /usr/bin/docker-compose

    wget --no-check-certificate -O /usr/lib/systemd/system/docker.service ${download_Url}/init/systemd/docker.service -t 5 -T 20
    wget --no-check-certificate -O /usr/lib/systemd/system/docker.socket ${download_Url}/init/systemd/docker.socket -t 5 -T 20
    wget --no-check-certificate -O /usr/lib/systemd/system/containerd.service ${download_Url}/init/systemd/containerd.service -t 5 -T 20

    systemctl enable docker.service
    systemctl enable docker.socket
    systemctl enable containerd.service
    
    systemctl start containerd.service
    systemctl start docker.socket
    systemctl start docker.service

}

Docker_Compose_Check(){

    is_docker_compose="0"
    if Command_Exists docker-compose; then
        is_docker_compose="1"
        DOCKER_COMPOSE="docker-compose"
    else 
        if Command_Exists docker; then
            Docker_compose="docker compose version"
            if $Docker_compose; then
                is_docker_compose="1"
                DOCKER_COMPOSE="docker compose"
            fi
        else
            is_docker_compose="0"
        fi

    fi
}

Docker_Compose_Install() {

    if [ $is_docker_compose == "0" ]; then
        Docker_Install
    fi

    Compose_Download_Url="$download_Url/install/src/docker-compose-$(uname -s)-$(uname -m)"
    Compose_Path="/usr/local/bin/docker-compose"
    New_Compose_Path="/usr/libexec/docker/cli-plugins/docker-compose"
    Compose_lin="/usr/bin/docker-compose"

    if [ ! -f $New_Compose_Path ]; then
        wget --no-check-certificate -t 5 -T 20 -O $New_Compose_Path $Compose_Download_Url
        chmod +x $New_Compose_Path
        rm -rf $Compose_lin
    fi

    if [ ! -f ${Compose_lin} ];then
        ln -s $New_Compose_Path $Compose_lin
    fi
}


Set_Firewall() {
    sshPort=$(cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}')
    if [ "${PM}" = "apt-get" ]; then
        if [ ! -f "/usr/bin/ufw" ] && [ ! -f "/bin/ufw" ] && ! Command_Exists "ufw"; then
            apt-get install -y ufw
        fi
        if [ -f "/usr/sbin/ufw" ]; then
            ufw allow 22/tcp >/dev/null 2>&1
            ufw allow 80/tcp >/dev/null 2>&1
            ufw allow 443/tcp >/dev/null 2>&1
            ufw allow ${SMTP_PORT}/tcp >/dev/null 2>&1
            ufw allow ${SMTPS_PORT}/tcp >/dev/null 2>&1
            ufw allow ${SUBMISSION_PORT}/tcp >/dev/null 2>&1
            ufw allow ${IMAP_PORT}/tcp >/dev/null 2>&1
            ufw allow ${IMAPS_PORT}/tcp >/dev/null 2>&1
            ufw allow ${POP_PORT}/tcp >/dev/null 2>&1
            ufw allow ${POPS_PORT}/tcp >/dev/null 2>&1
            ufw allow ${HTTP_PORT}/tcp >/dev/null 2>&1
            ufw allow ${HTTPS_PORT}/tcp >/dev/null 2>&1
            ufw allow ${sshPort}/tcp >/dev/null 2>&1
            # ufw_status=$(ufw status)
            echo y | ufw enable >/dev/null 2>&1
            ufw default deny >/dev/null 2>&1
            ufw reload
        fi
    else
        if [ -f "/etc/init.d/iptables" ]; then
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${SMTP_PORT} -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${SMTPS_PORT} -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${SUBMISSION_PORT} -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${IMAP_PORT} -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${IMAPS_PORT} -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${POP_PORT} -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${POPS_PORT} -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${HTTP_PORT} -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${HTTPS_PORT} -j ACCEPT
            iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${sshPort} -j ACCEPT
            iptables -A INPUT -p icmp --icmp-type any -j ACCEPT
            iptables -A INPUT -s localhost -d localhost -j ACCEPT
            iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
            iptables -P INPUT DROP
            service iptables save
            sed -i "s#IPTABLES_MODULES=\"\"#IPTABLES_MODULES=\"ip_conntrack_netbios_ns ip_conntrack_ftp ip_nat_ftp\"#" /etc/sysconfig/iptables-config
            iptables_status=$(service iptables status | grep 'not running')
            if [ "${iptables_status}" == '' ]; then
                service iptables restart
            fi
        else
            AliyunCheck=$(cat /etc/redhat-release | grep "Aliyun Linux")
            [ "${AliyunCheck}" ] && return
            if [ ! -f "/usr/bin/firewall-cmd" ] && [ ! -f "/bin/firewall-cmd" ] && ! Command_Exists "firewall-cmd"; then
                yum install firewalld -y
            fi
            [ "${Centos8Check}" ] && yum reinstall python3-six -y
            systemctl enable firewalld
            systemctl start firewalld
            firewall-cmd --set-default-zone=public >/dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=22/tcp >/dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=80/tcp >/dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=443/tcp > /dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${SMTP_PORT}/tcp >/dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${SMTPS_PORT}/tcp >/dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${SUBMISSION_PORT}/tcp >/dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${IMAP_PORT}/tcp >/dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${IMAPS_PORT}/tcp >/dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${POP_PORT}/tcp >/dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${POPS_PORT}/tcp >/dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${HTTP_PORT}/tcp >/dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${HTTPS_PORT}/tcp >/dev/null 2>&1
            firewall-cmd --permanent --zone=public --add-port=${sshPort}/tcp >/dev/null 2>&1
            firewall-cmd --reload
        fi
    fi
}


Check_apt_status(){

    MAX_RETRIES=30
    retries=0

    while [ $retries -lt $MAX_RETRIES ]; do
        output=$(ps aux| grep -E '(apt|apt-get)\s' 2>&1)
        check_output=$(echo "$output" | grep -E '(apt|apt-get)\s')
        
        # If check_output is empty, terminate the loop
        if [ -z "$check_output" ]; then
            break
        fi

        retries=$((retries + 1))

        echo "apt-get is in use, it will automatically exit after ${retries}/${MAX_RETRIES} times, try again after 10 seconds..."
        echo "$check_output"
        wait_msg="Please wait "
        wait_time="10"
        Bored_waiting
        
    done

    if [ $retries -ge $MAX_RETRIES ]; then
        echo "$output" > /tmp/waf_install_log.txt
        Red_Error "ERROR: apt-get command exceeds the maximum wait times: ${MAX_RETRIES}. Do not use the apt/apt-get command or install software during installation, please try to reinstall!"
    fi

}


Check_Connect_PgSql(){

    MAX_RETRIES=10
    retries=0

    while [ $retries -lt $MAX_RETRIES ]; do
        output=$(docker exec -i -e PGPASSWORD=${DBPASS} ${PGSQL_CONTAINER_NAME} psql -U ${DBUSER} -d ${DBNAME} -c "SELECT 1;" 2>&1)
        if [ $? -eq 0 ]; then
            PgSql_run="1"
            break
            # When equal to 0, exit the loop
        fi

        retries=$((retries + 1))

        echo "PgSql failed to connect, try again after 10 seconds, ${retries}/${MAX_RETRIES}..."

        if [[ "${retries}" == "1" ]] || [[ "${retries}" == "${MAX_RETRIES}" ]]; then
        # Only the first and last print information
            echo "$connect_PgSql"
        fi
        wait_msg="Please wait.."
        wait_time="10"
        Bored_waiting
        
    done

    if [ $retries -ge $MAX_RETRIES ]; then
        Red_Error "ERROR: The maximum number of retrys exceeded, and the connection to PgSql cannot be connected. Please try reinstalling!"
    fi

}


Domain_DKIM_record(){
    ## DKIM key generation
    docker exec -i -e BILLIONMAIL_HOSTNAME=${BILLIONMAIL_HOSTNAME} ${RSPAMD_CONTAINER_NAME} bash -c 'cat << "EOF" > /tmp/1.sh
#!/bin/bash
if [ ! -d "/var/lib/rspamd/dkim/${BILLIONMAIL_HOSTNAME}/" ]; then
    mkdir -p "/var/lib/rspamd/dkim/${BILLIONMAIL_HOSTNAME}/"
fi
if [ -f "/var/lib/rspamd/dkim/${BILLIONMAIL_HOSTNAME}/default.private" ] && [ -f "/var/lib/rspamd/dkim/${BILLIONMAIL_HOSTNAME}/default.pub" ]; then
    #echo "DKIM key already exists, skipping generation."
    exit 0
fi

rspamadm dkim_keygen -s 'default' -b 1024 -d {domain} -k "/var/lib/rspamd/dkim/${BILLIONMAIL_HOSTNAME}/default.private" > "/var/lib/rspamd/dkim/${BILLIONMAIL_HOSTNAME}/default.pub"
if [ $? -eq 0 ]; then
    # Define the root directory for private keys
    DKIM_KEYS_DIR="/var/lib/rspamd/dkim"
    # Configuration file path
    CONFIG_FILE="/etc/rspamd/local.d/dkim_signing.conf"
    # Check if the configuration file exists, if not, create it
    if [ ! -f "${CONFIG_FILE}" ]; then
        touch "${CONFIG_FILE}"
        echo "${CONFIG_FILE}"
        echo "domain {" > "${CONFIG_FILE}"
        echo "#BT_DOMAIN_DKIM_BEGIN" >> "${CONFIG_FILE}"
        echo "#BT_DOMAIN_DKIM_END" >> "${CONFIG_FILE}"
        echo "}" >> "${CONFIG_FILE}"
    fi
    # Scan the DKIM_KEYS_DIR directory to get all domains
    DOMAINS=()
    for DOMAIN_DIR in "${DKIM_KEYS_DIR}"/*; do
        if [ -d "${DOMAIN_DIR}" ]; then
            DOMAIN_NAME=$(basename "${DOMAIN_DIR}")
            PRIVATE_KEY_PATH="${DOMAIN_DIR}/default.private"
            if [ -f "${PRIVATE_KEY_PATH}" ]; then
                DOMAINS+=("${DOMAIN_NAME}:${PRIVATE_KEY_PATH}")
            else
                echo "Warning: Private key file ${PRIVATE_KEY_PATH} for domain ${DOMAIN_NAME} does not exist, skipping configuration."
            fi
        fi
    done
    # Add domain configurations
    for DOMAIN in "${DOMAINS[@]}"; do
        DOMAIN_NAME=$(echo "${DOMAIN}" | cut -d':' -f1)
        PRIVATE_KEY_PATH=$(echo "${DOMAIN}" | cut -d':' -f2)
        # Check if the domain already exists
        if grep -wq "${DOMAIN_NAME}" "${CONFIG_FILE}"; then
            # echo "Domain ${DOMAIN_NAME} already exists, skipping configuration."
            continue
        fi
        # Insert domain configuration between #BT_DOMAIN_DKIM_BEGIN and #BT_DOMAIN_DKIM_END
        sed -i "/^#BT_DOMAIN_DKIM_BEGIN$/a #${DOMAIN_NAME}_DKIM_BEGIN\n  ${DOMAIN_NAME} {\n    selectors [\n     {\n       path: \"${PRIVATE_KEY_PATH}\";\n       selector: \"default\"\n     }\n   ]\n }\n#${DOMAIN_NAME}_DKIM_END" "${CONFIG_FILE}"
        # echo "Domain ${DOMAIN_NAME} has been successfully added to the configuration file."
    done
    # echo "DKIM configuration update completed."
else
    echo -e "DKIM key generation failed!"
    exit 1
fi
chmod 755 -R "/var/lib/rspamd/dkim/${BILLIONMAIL_HOSTNAME}/"
EOF'
    docker exec -i -e BILLIONMAIL_HOSTNAME=${BILLIONMAIL_HOSTNAME} ${RSPAMD_CONTAINER_NAME} bash /tmp/1.sh && rm -f /tmp/1.sh
    DKIM_RECORD=$(docker exec ${RSPAMD_CONTAINER_NAME} cat "/var/lib/rspamd/dkim/${BILLIONMAIL_HOSTNAME}/default.pub")
    # echo "DKIM RECORD: ${DKIM_RECORD}"
}


Domain_record() {

    IPV4_ADDRESS=$(curl -sS -4 --connect-timeout 10 -m 20 https://ifconfig.me)
    if [ -z "${IPV4_ADDRESS}" ]; then
        IPV4_ADDRESS=$(curl -sSk --connect-timeout 10 -m 20 https://www.aapanel.com/api/common/getClientIP)
    fi
    ipv4_regex="^([0-9]{1,3}\.){3}[0-9]{1,3}$"
    if [[ ${IPV4_ADDRESS} =~ ${ipv4_regex} ]]; then        
        echo "${IPV4_ADDRESS}" >/dev/null 2>&1
    elif [ -z "${IPV4_ADDRESS}" ]; then
        IPV4_ADDRESS="YOUR_SERVER_IPV4_ADDRESS"
    fi
    echo -e ""
    echo -e "\e[31mPlease add the following record to your domain name\e[0m"
    echo -e "==========================================================="
    echo -e " Type | Host record    |    IPv4 address   |"
    echo -e "  \e[1;33mA\e[0m   | \e[1;33mmail.${BILLIONMAIL_HOSTNAME}\e[0m | \e[1;33m${IPV4_ADDRESS}\e[0m |"
    echo -e "==========================================================="
    echo -e " Type | Host record | MX priority |  Record value    "
    echo -e "  \e[1;33mMX\e[0m  |     \e[1;33m@\e[0m       |      \e[1;33m10\e[0m     | \e[1;33mmail.${BILLIONMAIL_HOSTNAME}\e[0m "
    echo -e "==========================================================="
    if [ "${IPV4_ADDRESS}" ]; then
        echo -e " Type | Host record |    Record value   |"
        echo -e "  \e[1;33mTXT\e[0m |     \e[1;33m@\e[0m       | \e[1;33mv=spf1 +a +mx +ip4:${IPV4_ADDRESS} -all\e[0m |"
    else
        echo -e " Type | Host record |    Record value   |"
        echo -e "  \e[1;33mTXT\e[0m |     \e[1;33m@\e[0m       | \e[1;33mv=spf1 +a +mx -all\e[0m |"
    fi
    echo -e "==========================================================="
    echo -e " Type | Host record |    Record value     |"
    echo -e "  \e[1;33mTXT\e[0m |   \e[1;33m_dmarc\e[0m    | \e[1;33mv=DMARC1;p=quarantine;rua=mailto:admin@${BILLIONMAIL_HOSTNAME}\e[0m |"
    echo -e "==========================================================="

    Domain_DKIM_record

    if [ "${DKIM_RECORD}" ]; then
        DKIM_RECORD=$(echo "${DKIM_RECORD}" | awk -F'"' '{print $2 $4}' | tr -d '[:space:]')
        #echo "DKIM RECORD: ${DKIM_RECORD}"
        echo -e " Type |  Host record       |    Record value     |"
        echo -e "  \e[1;33mTXT\e[0m | \e[1;33mdefault._domainkey\e[0m | \e[1;33m${DKIM_RECORD}\e[0m |<-- Start from \"v=DKIM1\" end, A single line."
        echo -e "==========================================================="
    else
        echo -e "${BILLIONMAIL_HOSTNAME} DKIM key generation failed!"
    fi
}

Init_Billionmail()
{
    # SQL file path
    SQL_FILE="./init.sql"
    if [ ! -f "${SQL_FILE}" ]; then
        Red_Error "SQL The file does not exist: ${SQL_FILE}"
    fi

    if docker ps --format '{{.Names}}' | grep -q "^${PGSQL_CONTAINER_NAME}$"; then
        
        # Test whether it is possible to connect
        Check_Connect_PgSql

        echo "Importing database..."
        docker exec -i -e PGPASSWORD=${DBPASS} ${PGSQL_CONTAINER_NAME} psql -U ${DBUSER} -d ${DBNAME} < ${SQL_FILE}
        if [ $? -eq 0 ]; then
            echo "Database import was successful!"
        else
            Red_Error "Database import failed!"
        fi
        echo "Creating domain..."
        BILLIONMAIL_HOSTNAME=$(echo "${BILLIONMAIL_HOSTNAME}" | tr '[:upper:]' '[:lower:]')
        Check_domain=$(docker exec -i -e PGPASSWORD=${DBPASS} ${PGSQL_CONTAINER_NAME} psql -U ${DBUSER} -d ${DBNAME} -c "SELECT * FROM domain WHERE domain = '${BILLIONMAIL_HOSTNAME}';" | grep -w "^ ${BILLIONMAIL_HOSTNAME}")
        if [ -z "${Check_domain}" ]; then
            # Create a domain
            docker exec -i -e PGPASSWORD=${DBPASS} ${PGSQL_CONTAINER_NAME} psql -U ${DBUSER} -d ${DBNAME} -c "INSERT INTO domain (domain, a_record, mailboxes, mailbox_quota, quota, rate_limit, create_time, active)
            VALUES ('${BILLIONMAIL_HOSTNAME}', 'mail.${BILLIONMAIL_HOSTNAME}', 500, 5368709120, 5368709120, 12, ${create_time}, 1);"
            if [ $? -eq 0 ]; then
                echo "Domain creation was successful!"
                Domain_DKIM_record
            else
                Red_Error "Domain creation failed!"
            fi
        else
            echo ""${Check_domain}" Domain already exists!"
        fi

        # Create a mailbox
        if [ -z "${mailbox}" ]; then
            mailbox=$(LC_ALL=C </dev/urandom tr -dc a-z0-9 2> /dev/null | head -c 6)
            echo "Generate mailbox: ${mailbox}"
        else
            mailbox=$(echo "${mailbox}" | tr '[:upper:]' '[:lower:]')
        fi
        Generate_mailbox_password=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 16)
        #echo "Generate_mailbox_password: ${Generate_mailbox_password}"
        Encrypt_mailbox_password=$(docker exec -i ${DOVECOT_CONTAINER_NAME} doveadm pw -s MD5-CRYPT -p "${Generate_mailbox_password}" | sed 's/{MD5-CRYPT}//')
        if [ $? -eq 0 ]; then
            echo "Generate_mailbox_password: ${Generate_mailbox_password}"
            echo "mailbox_password: ${Encrypt_mailbox_password}"
        else
            # Generate the default password after failure: BILLIONMAIL
            Generate_mailbox_password="BILLIONMAIL"
            Encrypt_mailbox_password='$1$ELBUCcYE$TbdGKBvLkFbjQguDbi3s01'
            echo "Generate_mailbox_password--default: ${Generate_mailbox_password}"
            Default_password=1
        fi

        if [ "${Default_password}" != 1 ]; then
            # password_encode 
            # Base64 encoding of strings
            b64_data=$(echo -n "${Generate_mailbox_password}" | base64)
            # Convert characters to hexadecimal
            password_encode=$(echo -n "${b64_data}" | while IFS= read -r -n1 char; do printf "%02x" "'$char"; done)
            echo "password_encode: ${password_encode}"
            if [ -z ${password_encode} ]; then
                b64_data=$(echo -n "${Generate_mailbox_password}" | base64)
                password_encode=$(echo -n "${b64_data}" | od -A n -t x1 | tr -d ' \n')
                echo "password_encode: ${password_encode}"
            fi
        else
            password_encode="516b6c4d54456c50546b31425355773d"
        fi

        Check_mailbox=$(docker exec -i -e PGPASSWORD=${DBPASS} ${PGSQL_CONTAINER_NAME} psql -U ${DBUSER} -d ${DBNAME} -c "SELECT * FROM mailbox WHERE username = '${mailbox}@${BILLIONMAIL_HOSTNAME}';" | grep -w "${mailbox}@${BILLIONMAIL_HOSTNAME}")
        if [ -z "${Check_mailbox}" ]; then
            INSERT_mailbox='INSERT INTO mailbox (username, password, password_encode, full_name, is_admin, maildir, quota, local_part, domain, create_time, update_time, active)
            VALUES (
                '\'${mailbox}@${BILLIONMAIL_HOSTNAME}\'',
                '\'${Encrypt_mailbox_password}\'',
                '\'${password_encode}\'',
                '\'${mailbox}\'',
                0,
                '\'${mailbox}@${BILLIONMAIL_HOSTNAME}/\'',
                5368709120,
                '\'${mailbox}\'',
                '\'${BILLIONMAIL_HOSTNAME}\'',
                '${create_time}',
                '${create_time}',
                1
            );'
            # echo "$INSERT_mailbox"
            docker exec -i -e PGPASSWORD=${DBPASS} ${PGSQL_CONTAINER_NAME} psql -U ${DBUSER} -d ${DBNAME} -c "$INSERT_mailbox"
            if [ $? -eq 0 ]; then
                echo "Mailbox creation was successful!"
            else
                Red_Error "Mailbox creation failed!"
            fi
            #docker exec -i -e PGPASSWORD=${DBPASS} ${PGSQL_CONTAINER_NAME} psql -U ${DBUSER} -d ${DBNAME} -c "SELECT * FROM mailbox WHERE username = '${mailbox}@${BILLIONMAIL_HOSTNAME}';"
        else
            echo ""${Check_mailbox}" Mailbox already exists!"
        fi

    else
        Red_Error "PgSql container does not exist!"
    fi

}


Billionmail(){
    Check_Port=$(ss -tlnp | grep -E ":(${HTTP_PORT})\b")
    if [ ! -z "${Check_Port}" ]; then
        HTTP_PORT=5678
        Check_Port=$(ss -tlnp | grep -E ":(${HTTP_PORT})\b")
    fi
    if [ ! -z "${Check_Port}" ]; then
        echo -e "${HTTP_PORT} Already used, random ports are being used"
        while true; do
        HTTP_PORT=$((RANDOM % 55535 + 10000))
        if ! ss -tln | grep -q ":${HTTP_PORT} "; then
            echo "${HTTP_PORT}"
            break
        fi
        done
    fi

    Check_Port22=$(ss -tlnp | grep -E ":(${HTTPS_PORT})\b")
    if [ ! -z "${Check_Port22}" ]; then
        HTTPS_PORT=5679
        Check_Port22=$(ss -tlnp | grep -E ":(${HTTPS_PORT})\b")
    fi
    if [ ! -z "${Check_Port22}" ]; then
        echo -e "${HTTPS_PORT} Already used, random ports are being used"
        while true; do
        HTTPS_PORT=$((RANDOM % 55535 + 10000))
        if ! ss -tln | grep -q ":${HTTPS_PORT} "; then
            echo "${HTTPS_PORT}"
            break
        fi
        done
    fi

    cat << EOF > billionmail.conf
# Default BillionMail Username password
ADMIN_USERNAME=${ADMIN_USERNAME}
ADMIN_PASSWORD=${ADMIN_PASSWORD}

# Manage Safe entrance
SafePath=${SafePath}

# BILLIONMAIL_HOSTNAME configuration, Postfix myhostname configuration
BILLIONMAIL_HOSTNAME=${ADD_MAIL_BILLIONMAIL_HOSTNAME}

# pgsql NAME and USER and PASSWORD configuration

DBNAME=${DBNAME}
DBUSER=${DBUSER}
DBPASS=${DBPASS}

# REDIS PASSWORD configuration
REDISPASS=${REDISPASS}


## MAIL Ports
SMTP_PORT=${SMTP_PORT}
SMTPS_PORT=${SMTPS_PORT}
SUBMISSION_PORT=${SUBMISSION_PORT}
IMAP_PORT=${IMAP_PORT}
IMAPS_PORT=${IMAPS_PORT}
POP_PORT=${POP_PORT}
POPS_PORT=${POPS_PORT}
REDIS_PORT=${REDIS_PORT}
SQL_PORT=${SQL_PORT}

## Manage Ports
HTTP_PORT=${HTTP_PORT}
HTTPS_PORT=${HTTPS_PORT}

# Web deployment base path. Keep empty for root deployment.
# Set to /billionmail when embedding behind aaPanel path proxy.
WEB_BASE_PATH=

# Shared secret used by aaPanel to request trusted BillionMail SSO tokens.
# Keep empty to disable aaPanel SSO.
AAPANEL_SSO_SECRET=

# You can use this script to set the time zone for your container.
# See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for a list of timezones"
# echo -e "Use a column named "TZ identifier" + note the column named "Notes""

TZ=${BILLIONMAIL_TIME_ZONE}

# Default containers IPV4 intranet segment
IPV4_NETWORK=172.66.1

# Enable fail2ban Access restrictions, specify that the IP exceeds the access limit
FAIL2BAN_INIT=y

# Number of days to keep log backup
RETENTION_DAYS=7

EOF
    \cp -rf billionmail.conf .env
    if [ ! -f ".env" ]; then
        echo -e "Error: Failed to create .env file"
        exit 1
    fi

    SSL_path=ssl-self-signed
    if [ ! -d "ssl-self-signed" ]; then
        mkdir ssl-self-signed
    fi
    openssl genrsa -out ${SSL_path}/key.pem 2048
    openssl req -x509 -new -nodes -key ${SSL_path}/key.pem -sha256 -days 3650 -out ${SSL_path}/cert.pem \
    -subj "/C=US/ST=State/L=City/O=${BILLIONMAIL_HOSTNAME}/OU=${BILLIONMAIL_HOSTNAME}/CN=*.${BILLIONMAIL_HOSTNAME}" -nodes
    mkdir ssl
    cp -d -n ${SSL_path}/* ssl/

    echo -e "Execute ${DOCKER_COMPOSE} up -d"
    if  [ ! -s "docker-compose.yml" ]; then
        ls -al
        Red_Error "docker-compose.yml not found."
    fi
    ${DOCKER_COMPOSE} pull
    ${DOCKER_COMPOSE} up -d
    if [ $? -eq 0 ]; then
        echo -e "Billionmail installation completed successfully!"
    else
        echo ""
        echo -e "--------------------------------------------------"
        Check_Port
        echo -e "\e[1;31m Startup error,\e[0m please resolve it according to the prompts, otherwise it will affect the use!"
        sleep 5
        bash bm.sh status
        echo -e "--------------------------------------------------"
        echo ""
    fi

    # echo -e "Initialize the data..."
    # sleep 5
    # Init_Billionmail

    [ ! -d "/opt" ] && mkdir /opt
    echo "${PWD_d}" > /opt/PWD-Billion-Mail.txt
    ln -sf ${PWD_d}/bm.sh /usr/bin/bm
    chmod +x ${PWD_d}/bm.sh

}


Install_Main(){
    # Check_Port
    LXC_install_tips

    Get_Pack_Manager
    if [ "$PM" == "yum" ]; then
        Install_RPM_Pack
    else
        Install_Deb_Pack
    fi

    set +e
    Docker_Check
    Docker_Compose_Check
    
    if [ "$is_docker" != "1" ]; then
        Docker_Download_Url_Check
        Docker_Install
        Docker_Compose_Check
    fi

    if [ "$is_docker_compose" != "1" ]; then
        Docker_Compose_Install
        Docker_Compose_Check
        if [ "$is_docker_compose" != "1" ]; then
            Red_Error "ERROR: Docker Compose installation failed, Please reinstall Docker Compose!"
        fi
    fi
   
    Docker_Start

    Billionmail
    
    Set_Firewall
    
}


Install_Main
# Domain_record

IPV4_ADDRESS=$(curl -sSf -4 --connect-timeout 10 -m 20 https://ifconfig.me)
if [ -z "${IPV4_ADDRESS}" ]; then
    IPV4_ADDRESS=$(curl -sSfk --connect-timeout 10 -m 20 https://www.aapanel.com/api/common/getClientIP)
fi
ipv4_regex="^([0-9]{1,3}\.){3}[0-9]{1,3}$"
if [[ ${IPV4_ADDRESS} =~ ${ipv4_regex} ]]; then        
    echo "${IPV4_ADDRESS}" >/dev/null 2>&1
elif [ -z "${IPV4_ADDRESS}" ]; then
    IPV4_ADDRESS="YOUR_SERVER_IPV4_ADDRESS"
fi
intenal_ip=$(ip addr | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -E -v "^127\.|^255\.|^0\." | head -n 1)
# echo -e "\e[31mPlease save the following information:\e[0m"
# if [ ${HTTPS_PORT} = "443" ]; then
#     echo -e "Webmail address: \e[1;33mhttps://${IPV4_ADDRESS}/roundcube/\e[0m"
# else
#     echo -e "Webmail address: \e[1;33mhttps://${IPV4_ADDRESS}:${HTTP_PORT}/roundcube/\e[0m"
# fi
# echo -e "Webmail Username(e-mail): \e[1;33m${mailbox}@${BILLIONMAIL_HOSTNAME}\e[0m Password: \e[1;33m${Generate_mailbox_password}\e[0m"
# echo -e ""
if [ ${HTTPS_PORT} = "443" ]; then
    echo -e "BillionMail Internet address: \e[1;33mhttps://${IPV4_ADDRESS}/${SafePath}\e[0m"
    echo -e "BillionMail Internal address: \e[1;33mhttps://${intenal_ip}/${SafePath}\e[0m"
else
    echo -e "BillionMail Internet address: \e[1;33mhttps://${IPV4_ADDRESS}:${HTTPS_PORT}/${SafePath}\e[0m"
    echo -e "BillionMail Internal address: \e[1;33mhttps://${intenal_ip}:${HTTPS_PORT}/${SafePath}\e[0m"
fi
echo -e "Username: \e[1;33m${ADMIN_USERNAME}\e[0m"
echo -e "Password: \e[1;33m${ADMIN_PASSWORD}\e[0m"
echo -e ""
echo -e "Tip: Use \e[33m bm \e[0m or \e[33mbash bm.sh\e[0m to View login info etc."

# Install
curl -o /dev/null -fsSLk --connect-time 10 -X POST "https://www.aapanel.com/api/panel/panel_count_daily?name=billionmail" >/dev/null 2>&1