#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
source "$(dirname "$0")/lib/ulib/ulib" || exit 1
urequire DEFAULTS template apache.tools
apacheconfig_initvars

function display_help() {
    uecho "$scriptname: Gérer la configuration d'un serveur web apache

USAGE
    $scriptname -c
    $scriptname -t -- args...

OPTIONS
    -c, --create
        Créer un nouveau répertoire de configuration pour un hôte
    -d, --destdir DESTDIR[=$TEMPLATECTL_NAME]
        Nom du répertoire local de configuration.
    -f,--full
    --partial
        Indiquer respectivement que la configuration est complète ou partielle.
        Avec la configuration complète, le serveur peut être complètement
        configuré avec tous les fichiers présents. Avec la configuration
        partielle, uniquement les informations spécifiques à un service en
        particulier sont disponibles.
        Cette option est utilisée avec --create. Par défaut, la configuration
        est partielle.
        Pour le moment, la seule différence est que --full crée un fichier de
        configuration nommé .apacheconfig alors que --partial crée un fichier
        nommé apacheconfig.conf qui est visible et donc découvrable et éditable
        plus facilement

    -t, --template [OPT]
        Gérer les fichiers du répertoire local avec templatectl. La valeur de
        cette option est utilisée comme argument court pour l'invocation de
        templatectl, e.g
            $scriptname -tm args
        est équivalent à
            templatectl -m args
        Les arguments qui restent sont passés tels quels à templatectl
        Les options courantes de templatectl -l, -v, -m, -L sont disponibles
        directement
    --help-template
        Afficher l'aide concernent la gestion des templates.
        Equivalent à -t -- --help
    -h, --host HOST
        Spécifier l'hôte. Equivalent à -v host=HOST
    --sysname SYSNAME
    --sysdist SYSDIST
    -s, --sysver SYSVER
        Spécifier la distribution pour laquelle synchroniser le template. Par
        défaut, choisir les valeurs correspondantes au système courant.
        Les options -7 et -8 sont des aliases respectivement pour -s wheezy et
        -s jessie, parce que les fichiers par défaut ont changé à partir de
        debian jessie.

    -u, --update, --deploy
        Mettre à jour la configuration système à partir du répertoire local.
        Lors du déploiement de la configuration, les valeurs des variables
        dynamiques sont remplacées dans les fichiers destination.
        Les arguments qui restent sont passés tels quels à apache_autoconf
    -p, --pull
        Faire 'git pull' avant --update
    -F, --fix-ip
        Corriger les lignes de la forme '<VirtualHost *:PORT>#*ip:IP' et les
        remplacer par '<VirtualHost IP:PORT>'
        Cela permet de déployer une version de production des fichiers de
        configuration.
    -N, --network-config
        Mettre aussi à jour la configuration réseau.
    --no-post-update
        Ne pas lancer le script post-update.sh après le déploiement s'il existe.
        Le script est lancé avec les mêmes arguments que apacheconfig_deploy()
        la fonction définie dans le module apache.tools
    -r, --certsdir CERTSDIR
        Spécifier le cas échéant le répertoire contenant les certificats à
        déployer. Cet argument est requis si le répertoire certsconf/ existe,
        sauf si les certificats sont déjà déployés.

    --localhosts
        Créer dans le fichier /etc/hosts tous les noms d'hôte ayant un suffixe
        .local mentionnés dans les fichiers de site. Cette option est utile pour
        le développement et les tests.
    -C, --one-conf CONF
        Ne déployer que le fichier de configuration spécifié. Cette option est
        utilisée avec --deploy et est utile pour le développement et les tests.
    -M, --one-module MODULE
        Ne déployer que le fichier de module spécifié. Cette option est utilisée
        avec --deploy et est utile pour le développement et les tests.
    -S, --one-site SITE
        Ne déployer que le fichier de site spécifié. Cette option est utilisée
        avec --deploy ou --localhosts et est utile pour le développement et les
        tests.

    -k, --new-site HOST.TLD
        Créer une définition pour un nouveau site à partir des fichiers du
        répertoires templates/
    -K, --new-site-templatedir TEMPLATEDIR
        Spécifier le répertoire source pour les templates de site utilisés par
        l'option --new-site. Par défaut, utiliser le répertoire templates/ situé
        dans le répertoire de configuration.
        Si TEMPLATEDIR est un nom simple sans séparateur de chemin '/' et qu'un
        répertoire templates/TEMPLATEDIR existe, alors prendre ce répertoire-là
        comme source.
    --new-site-force
        Avec --new-site, utiliser le nom d'hôte fourni même s'il n'est pas
        pleinement qualifié"
}

action=
destdir=
nohideconfig=auto
templateopt=
FULLCONF=
pull=
fixip=
netconf=
no_post_update=
aac_certsdir=
bits=
oneconf=
onemodule=
onesite=
site_host=
site_templdir=
site_force=
args=(
    --help '$exit_with display_help'
    -c,--create action=create
    -d:,--destdir: destdir=
    --no-hideconfig nohideconfig=1
    --hideconfig nohideconfig=
    -f,--full FULLCONF=1
    --partial FULLCONF=
    -t::,--template:: '$set@ templateopt; action=template'
    --help-template '$templateopt=-help; action=template'
    -l,--list '$templateopt=l; action=template'
    -v:,--var: TEMPLATECTL_VARS
    -m,--merge '$templateopt=m; action=template'
    -L,--list-vars '$templateopt=L; action=template'
    -h:,--host: '$array_add TEMPLATECTL_VARS host="$value_"'
    --sysname: '$array_add TEMPLATECTL_VARS sysname="$value_"'
    --sysdist: '$array_add TEMPLATECTL_VARS sysdist="$value_"'
    -s:,--sysver: '$array_add TEMPLATECTL_VARS sysver="$value_"'
    -6,--squeeze '$array_add TEMPLATECTL_VARS sysver=squeeze'
    -7,--wheezy '$array_add TEMPLATECTL_VARS sysver=wheezy'
    -8,--jessie '$array_add TEMPLATECTL_VARS sysver=jessie'
    --bits: bits=
    -u,--update,--deploy action=deploy
    -p,--pull pull=1
    -F,--fix-ip fixip=1
    -N,--network-config netconf=1
    --no-post-update no_post_update=1
    -r:,--certsdir: aac_certsdir=
    --localhosts action=localhosts
    -C:,--one-conf: oneconf=
    -M:,--one-module: onemodule=
    -S:,--one-site: onesite=
    -k:,--new-site: '$action=new-site; set@ site_host'
    -K:,--new-site-templatedir: site_templdir=
    --new-site-force site_force=
)
parse_args "$@"; set -- "${args[@]}"

if [ "$nohideconfig" == auto ]; then
    [ -n "$FULLCONF" ] && nohideconfig= || nohideconfig=1
fi

if [ -n "$pull" ]; then
    estep "Mise à jour du dépôt"
    if [ -n "$destdir" ]; then
        [ -d "$destdir" ] || die "$destdir: répertoire introuvable"
        (cd "$destdir" && git pull) || die
    else
        git pull || die
    fi
fi

apacheconfig_loadconf "$destdir" "$nohideconfig" || die
apacheconfig_sysinfos "$sysname" "$sysdist" "$sysver" "$bits"

################################################################################
if [ "$action" == create ]; then
    if [ -n "$autocreate" -a ! -d "$destdir" ]; then
        estepn "Création automatique de $(ppath "$destdir")"
        mkdir -p "$destdir" || die
    fi
    [ -d "$destdir" ] || die "$destdir: répertoire introuvable"

    [ -n "$host" ] || host="$1"
    if [ -n "$host" ]; then
        read_value -i "Veuillez entrer le nom d'hôte" host "$host"
    else
        check_interaction -c && einfo "Vous pouvez entrer un nom d'hôte spécifique pour la nouvelle configuration, ou laisser la valeur par défaut @@dhost@@ pour qu'il soit calculé dynamiquement lors du déploiement"
        read_value "Veuillez entrer le nom d'hôte" host @@dhost@@
    fi
    __template_set_var host "$host"

    if [ -f "$config" ]; then
        ask_yesno "Le fichier $(ppath "$config") sera écrasé. Voulez-vous continuer?" O || die
        rm -f "$config" || die
    fi
    templatectl -d "$destdir" --config "$config" ${nohideconfig:+--no-hide-config} --no-load-vars -m --write-vars

################################################################################
elif [ "$action" == template ]; then
    __TEMPLATECTL_HELP="USAGE: $scriptname -t -- args...

$__TEMPLATECTL_HELP"
    templatectl -d "$destdir" --config "$config" --no-load-vars ${templateopt:+-$templateopt} "$@"

################################################################################
elif [ "$action" == deploy -o "$action" == localhosts ]; then
    [ -d "$destdir" ] || die "$destdir: répertoire introuvable"

    args=(
        -d "$destdir" --$action
        ${fixip:+--fix-ip}
        ${netconf:+--network-config}
        ${no_post_update:+--no-post-update}
        ${aac_certsdir:+-r "$aac_certsdir"}
        ${oneconf:+--one-conf "$oneconf"}
        ${onemodule:+--one-module "$onemodule"}
        ${onesite:+--one-site "$onesite"}
    )
    # sur une ligne séparée parce que $bits peut être vide
    [ -n "$custom_sysinfos" ] && array_add args --sysname "$sysname" --sysdist "$sysdist" --sysver "$sysver" --bits "$bits"
    for __name in "${TEMPLATE_DYNAMIC_VARS[@]}"; do
        array_add args -v "$__name=${!__name}"
    done
    array_add args -- "$@"
    run_as_root "${args[@]}"

    if [ "$action" == deploy ]; then
        etitle "Mise à jour du système"
        apacheconfig_deploy \
            "$destdir" "$aac_certsdir" \
            "$config" "$oneconf" "$onemodule" "$onesite" \
            "$custom_sysinfos" "$sysname" "$sysdist" "$sysver" "$bits" \
            "$netconf" "$fixip" "$no_post_update" || die
        eend
    elif [ "$action" == localhosts ]; then
        etitle "Mise à jour de /etc/hosts"
        apacheconfig_localhosts "$destdir" "$aac_certsdir" "$onesite" || die
        eend
    fi

################################################################################
elif [ "$action" == new-site ]; then
    host="$site_host"
    templdir="$site_templdir"

    if [ -z "$templdir" -a -d "$destdir/templates" ]; then
        # si on ne précise pas le template à utiliser, alors afficher
        # éventuellement un menu si plusieurs templates sont disponibles
        templdirs=()
        if [ -n "$(list_all "$destdir/templates" "*SITE*")" ]; then
            array_add templdirs templates
            templdir=templates
        fi
        array_from_lines stempldirs "$(list_dirs "$destdir/templates" | grep -v SITE)"
        for stempldir in "${stempldirs[@]}"; do
            if [ -n "$(list_all "$destdir/templates/$stempldir" "*SITE*")" ]; then
                array_add templdirs "templates/$stempldir"
                [ -n "$templdir" ] || templdir="templates/$stempldir"
            fi
        done
        if [ ${#templdirs[*]} -gt 1 ]; then
            simple_menu templdir templdirs -t "Choix du répertoire des modèles" -m "Veuillez choisir le modèle à utiliser"
        fi
        templdir="$destdir/$templdir"
    fi

    if [[ "$templdir" != */* ]] && [ -d "$destdir/templates/$templdir" ]; then
        templdir="$destdir/templates/$templdir"
    elif [ -z "$templdir" ]; then
        templdir="$destdir/templates"
    fi
    [ -d "$templdir" ] || die "$templdir: répertoire introuvable"
    force="$site_force"

    clrtempl=
    ssltempl=
    certstempl=
    wwwtempl=
    array_from_lines clrtempls "$(list_files "$templdir" "*SITE*.conf")"
    array_from_lines ssltempls "$(list_files "$templdir" "*SITE*.ssl.conf")"
    array_from_lines certstempls "$(list_files "$templdir" "*SITE*-certs.conf")"
    for xtempl in "${ssltempls[@]}" "${certstempls[@]}"; do
        array_del clrtempls "$xtempl"
    done
    [ ${#clrtempls[*]} -gt 0 ] && clrtempl="${clrtempls[0]}"
    [ ${#ssltempls[*]} -gt 0 ] && ssltempl="${ssltempls[0]}"
    [ ${#certstempls[*]} -gt 0 ] && certstempl="${certstempls[0]}"
    array_from_lines wwwtempls "$(list_dirs "$templdir" "*SITE*")"
    [ ${#wwwtempls[*]} -gt 0 ] && wwwtempl="${wwwtempls[0]}"

    found=
    for i in "$clrtempl" "$ssltempl" "$certstempl" "$wwwtempl"; do
        [ -n "$i" ] && { found=1; break; }
    done
    [ -n "$found" ] || die "Aucun template disponible"

    if [ -z "$force" ] && [[ "$host" != *.* ]]; then
        die "$host n'est pas un nom d'hôte pleinement qualifié"
    fi

    hostip=
    for i in "$clrtempl" "$ssltempl"; do
        [ -n "$i" -a -f "$templdir/$i" ] || continue
        quietgrep SITE_IP "$templdir/$i" && { hostip=1; break; }
    done
    if [ -n "$hostip" ]; then
        # Il y a un champ SITE_IP, il faut demander à l'utilisateur l'adresse ip
        # correspondante
        [[ "$host" == *.* ]] && hostdomain="${host#*.}" || hostdomain=
        pri=
        hostip=
        i=0
        while [ $i -lt ${#PUBDOMAINS[*]} ]; do
            if [ "${PUBDOMAINS[$i]}" == "$hostdomain" ]; then
                pri="$VSPREFIX${host%$hostdomain}${PRIDOMAINS[$i]}"
                resolv_ips ips "$pri"
                if [ -n "$ips" ]; then
                    hostip="${ips[0]}"
                    break
                fi
            fi
            i=$(($i + 1))
        done
        if [ -z "$hostip" ]; then
            pri="$VSPREFIX$host"
            resolv_ips ips "$pri"
            [ -n "$ips" ] && hostip="${ips[0]}"
        fi
        if [ -n "$pri" -a -n "$hostip" ]; then
            enote "Correspondance automatique $host --> $pri"
            read_value "Veuillez confirmer l'adresse IP d'écoute" hostip "$hostip" N
        else
            enote "Vous devez saisir l'adresse IP privée correspondant à $host"
            read_value "Veuillez entrer l'adresse IP *privée* d'écoute" hostip "" N
        fi
        [ -n "$hostip" ] || ewarn "Vous avez choisi de ne pas spécifier d'adresse IP d'écoute. Il faudra corriger manuellement les fichiers générés"
    fi

    etitle "$host"
    hostname="${host%%.*}"
    clrconf="${clrtempl/SITE/$hostname}"
    sslconf="${ssltempl/SITE/$hostname}"
    certsconf="${certstempl/SITE/$hostname}"
    wwwdir="${wwwtempl/SITE/$hostname}"

    mkdir -p "$destdir/certsconf"
    mkdir -p "$destdir/sites"

    sedscript=
    [ -n "$hostip" ] && sedscript="$sedscript
s/SITE_IP/$hostip/g"
    sedscript="$sedscript
s/SITE.TLD/$host/g
s/SITE/$hostname/g"

    if [ -z "$clrtempl" ]; then
        :
    elif [ ! -f "$templdir/$clrtempl" ]; then
        ewarn "Le fichier $(ppath "$templdir/$clrtempl") n'existe pas. La copie ne sera pas complète"
    elif [ -f "$destdir/sites/$clrconf" ]; then
        ewarn "Le fichier sites/$clrconf existe déjà. Il ne sera pas écrasé."
    else
        estep "sites/$clrconf"
        sed "$sedscript" "$templdir/$clrtempl" >"$destdir/sites/$clrconf" || die
    fi

    if [ -z "$ssltempl" ]; then
        :
    elif [ ! -f "$templdir/$ssltempl" ]; then
        ewarn "Le fichier $(ppath "$templdir/$ssltempl") n'existe pas. La copie ne sera pas complète"
    elif [ -f "$destdir/sites/$sslconf" ]; then
        ewarn "Le fichier sites/$sslconf existe déjà. Il ne sera pas écrasé."
    else
        estep "sites/$sslconf"
        sed "$sedscript" "$templdir/$ssltempl" >"$destdir/sites/$sslconf" || die
    fi

    if [ -z "$certstempl" ]; then
        :
    elif [ ! -f "$templdir/$certstempl" ]; then
        ewarn "Le fichier $(ppath "$templdir/$certstempl") n'existe pas. La copie ne sera pas complète"
    elif [ -f "$destdir/certsconf/$certsconf" ]; then
        ewarn "Le fichier certsconf/$certsconf exite déjà. Il ne sera pas écrasé."
    else
        estep "certsconf/$certsconf"
        sed "$sedscript" "$templdir/$certstempl" >"$destdir/certsconf/$certsconf" || die
    fi

    if [ -z "$wwwtempl" ]; then
        :
    elif [ ! -d "$templdir/$wwwtempl" ]; then
        ewarn "Le répertoire $(ppath "$templdir/$wwwtempl") n'existe pas. La copie ne sera pas complète"
    elif [ -d "$destdir/$wwwdir" ]; then
        ewarn "Le répertoire $wwwdir existe déjà. Il ne sera pas écrasé."
    else
        estep "$wwwdir"
        cpdirnovcs "$templdir/$wwwtempl" "$destdir/$wwwdir" || die
        sed -i "$sedscript" "$destdir/$wwwdir/.udir" || die
    fi

    eend

    if [ -n "$wwwtempl" ]; then
        eimportant "Ne pas oublier le cas échéant de mettre à jour HTDMAPPINGS dans $(ppath "$config") e.g.
    HTDMAPPINGS=($wwwdir)"
    fi
fi
