#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8

function display_help() {
    uecho "$scriptname: Contrôler des applications WebObjects

USAGE
    $scriptname [options] action args
    wostart args...
    wostop args...
    wobounce args...
    worestart args...

OPTIONS
    -h HOST
        Spécifier l'hôte qui fait tourner le moniteur sous la forme host[:port]
    -p PASSWORD
        Spécifier le mot de passe pour le moniteur

ACTIONS
    Dans les arguments des actions ci-dessous, une application peut être
    spécifiée sous la forme App ou App.woa. Spécifier une application revient à
    spécifier toutes les instances configurées pour cette application.
    Si on spécifie un framework sous la forme Fwk.framework, cela revient à
    spécifier toutes les applications qui dépendent de ce framework.
    Sinon, une instance individuelle est de la forme App-N, où N est un entier
    positif.

    status
        afficher l'état des instances qui tournent actuellement
    version
        afficher la version de WebObjects installée
    wotaskd
    javamonitor
    woservices
        piloter wotaskd/javamonitor
    _create
        créer une instance par défaut dans javamonitor
    configure
        configurer un bundle
    tag
        ajouter une information de version à un bundle
    run
        lancer une application localement en mode debug
    download
        télécharger une application ou un framework
    start apps...
        démarrer une ou plusieurs applications
    stop apps...
        arrêter une ou plusieurs applications
    restart apps...
        relancer une ou plusieurs applications
    bounce apps...
        relancer une ou plusieurs applications en mode bounce"
}

SCRIPT_ALIASES=(
    wostart:start
    wostop:stop
    worestart:restart
    wobounce:bounce
    woservices:woservices
    woconf:configure
    wotag:tag
    worun:run
    wodownload:download
)
CMD_ALIASES=(
    v:version
    s:start
    k:stop t:stop
    r:restart
    b:bounce
    wot:wotaskd
    wom:javamonitor womonitor:javamonitor monitor:javamonitor
    wos:woservices
    conf:configure
    dl:download
)
DEFAULT_CMD=status

if [ "$#" -eq 1 -a "$1" == --nutools-makelinks ]; then
    # créer les liens
    scriptname="$(basename "$0")"
    for alias in "${SCRIPT_ALIASES[@]}"; do
        alias="${alias%:*}"
        ln -s "$scriptname" "$alias"
    done
    exit 0
fi

source "$(dirname "$0")/lib/ulib/ulib" || exit 1
urequire DEFAULTS

# Traduire le nom du script
for script_alias in "${SCRIPT_ALIASES[@]}"; do
    splitpair "$script_alias" src dest
    if [ "$scriptname" == "$src" ]; then
        eval "set -- $dest \"\$@\""
        break
    fi
done

set_defaults WOServices
# note: Il FAUT chager wondermonitor *après* avoir chargé les paramètres dans WOServices
urequire apache wondermonitor
compute_apache_prefixes
compute_webobjects_prefixes

parse_opts + "${PRETTYOPTS[@]}" \
    --help '$exit_with display_help' \
    @ args -- "$@" && set -- "${args[@]}" || die "$args"

[ -n "$*" ] || set -- "$DEFAULT_CMD"
CMD=
found_cmd=
while [ -z "$found_cmd" ]; do
    CMD="$1"; shift; found_cmd=1
    [ -n "$CMD" ] || break

    for cmd_alias in "${CMD_ALIASES[@]}"; do
        splitpair "$cmd_alias" src dest
        if [ "$CMD" == "$src" ]; then
            eval "set -- $dest \"\$@\""
            found_cmd=
            break
        fi
    done
done

################################################################################
if [ "$CMD" == "status" ]; then
    function __display_help() {
        uecho "woctl status: afficher l'état des applications configurées

USAGE
    woctl status [apps...]"
    }

    host=
    password=
    parse_opts "${PRETTYOPTS[@]}" \
        --help '$exit_with __display_help' \
        -h:,-H:,--host: host= \
        -p:,--password: password= \
        @ args -- "$@" && set -- "${args[@]}" || die "$args"

    check_compute_apps_localhost "$host" "$@" || die
    wom_getApplications appinfos "" "$host" "$password"
    compute_apps apps appinfos "$@" || die "Impossible de trouver les applications ou frameworks spécifiés"

    if [ -n "${apps[*]}" ]; then
        for app in "${apps[@]}"; do
            wom_info appinfos "$app" "$host" "$password" || die "$(get_error_msg $? "d'obtenir des informations sur $app")"
            for args in "${appinfos[@]}"; do
                eval "show_appinfo $args"
            done
        done
    else
        wom_info appinfos "" "$host" "$password" || die "$(get_error_msg $? "d'obtenir des informations sur $1")"
        for args in "${appinfos[@]}"; do
            eval "show_appinfo $args"
        done
    fi

################################################################################
elif [ "$CMD" == "version" ]; then
    function __display_help() {
        uecho "woctl version: afficher la version de WebObjects installée

USAGE
    woctl version"
    }

    parse_opts "${PRETTYOPTS[@]}" \
        --help '$exit_with __display_help' \
        @ args -- "$@" && set -- "${args[@]}" || die "$args"

    get_WOVERSION_prefix

################################################################################
elif [ "$CMD" == "_create" ]; then
    function __display_help() {
        uecho "woctl _create: créer une application dans le moniteur

USAGE
    woctl _create <AppName>

Une application nommée AppName qui lance le bundle \$WOAPPLICATIONS/AppName.woa
est configurée dans le moniteur. Une instance de cette application est créée.

OPTIONS
    -n COUNT
        Créer COUNT instances au lieu d'une seule"
    }

    host=
    password=
    count=
    parse_opts "${PRETTYOPTS[@]}" \
        --help '$exit_with __display_help' \
        -h:,-H:,--host: host= \
        -p:,--password: password= \
        -n:,--count: count= \
        @ args -- "$@" && set -- "${args[@]}" || die "$args"

    name="$1"
    [ -n "$name" ] || die "Vous devez spécifier le nom de l'application à créer"
    [ -n "$count" ] || count=1

    wom_getApplications appinfos
    for appinfo in "${appinfos[@]}"; do
        eval "appinfo=($appinfo)"
        if [ "${appinfo[0]}" == "$name" ]; then
            die "L'application $name existe déjà"
        fi
    done

    etitle "Création de l'application" \
        wom_addApplication "$name" "$host" "$password" || die "$(get_error_msg $?)"
    if [ "$count" -lt 1 ]; then
        enote "Aucune instance n'a été créée pour cette application"
    elif [ "$count" == 1 ]; then
        etitle "Création de l'instance" \
            wom_addInstance "$name" "$host" "$password" || die "$(get_error_msg $?)"
    else
        etitle "Création des instances"
        i=1
        while [ $i -le "$count" ]; do
            estep "Instance #$i"
            wom_addInstance "$name" "$host" "$password" || die "$(get_error_msg $?)"
            i=$(($i + 1))
        done
        eend
    fi

################################################################################
elif [ "$CMD" == "start" ]; then
    function __display_help() {
        uecho "woctl start: Démarrer une ou plusieurs instances

USAGE
    woctl start Application[.woa]...
    woctl start Application-N...
        Démarrer toutes les instances de l'application ou seulement l'instance
        spécifiée.
        Pour toutes les commandes start, si l'application ou l'instance tourne
        déjà, aucune opération n'est effectuée. Dans le cas contraire,
        l'autoRecover est activé pour chacune des applications qui ont été
        lancées avec succès.
    woctl start -a
        Lancer uniquement les applications mentionnées dans le fichier
        WOCONFIGURATION/AutoStart.txt dans l'ordre qui y est spécifié. Ce
        fichier contient une application/instance par ligne, et peut contenir
        des commentaires commençant par '#'
        Avec cette option, les arguments supplémentaires sont ignorés.
    woctl start -A
        Lancer toutes les applications configurées, dans l'ordre indiqué par le
        fichier WOCONFIGURATION/AutoStart.txt
        Les applications/instances qui ne sont pas mentionnées dans le fichier
        sont lancées en dernier.
        Avec cette option, les arguments supplémentaires sont ignorés.

OPTIONS
    -s  Démarrer les applications en utilisant l'ordre fourni par le fichier
        WOCONFIGURATION/AutoStart.txt
        Cette option est toujours active pour les options -a et -A
    -f  Forcer l'activation de l'autoRecover même si l'instance tourne déjà.
    -n  Ne pas activer l'autoRecover après le démarrage d'une application."
    }

    host=
    password=
    start_autostart=
    all_configured=
    apply_autostart_order=
    force_enable_autorecover=
    enable_autorecover=1
    parse_opts "${PRETTYOPTS[@]}" \
        --help '$exit_with __display_help' \
        -h:,-H:,--host: host= \
        -p:,--password: password= \
        -a start_autostart=1 \
        -A '$start_autostart=1; all_configured=1' \
        -s apply_autostart_order=1 \
        -f force_enable_autorecover=1 \
        -n enable_autorecover= \
        @ args -- "$@" && set -- "${args[@]}" || die "$args"

    # calculer la liste des applications puis les démarrer
    check_compute_apps_localhost "$host" "$@" || die
    wom_getApplications appinfos "" "$host" "$password"

    if [ -n "$start_autostart" -o -n "$apply_autostart_order" ]; then
        wom_getValidAndRunning valid_apps running_apps "$host" "$password" || die "$(get_error_msg $? "de charger la liste des applications")"
        check_autostart valid_apps || die
    fi

    if [ -n "$start_autostart" ]; then
        if [ -n "$all_configured" ]; then
            # Prendre toutes les applications configurées
            array_copy apps valid_apps
            apply_autostart_order=1
        else
            # Prendre les applications de $WOAUTOSTART
            get_autostart_order apps
        fi
        [ -n "${apps[*]}" ] || die "Aucune application configurée n'a été trouvée"
    else
        apps=("$@")
    fi

    compute_apps apps appinfos "${apps[@]}" || die "Impossible de trouver les applications ou frameworks spécifiés"
    if [ -n "$apply_autostart_order" ]; then
        get_autostart_order autostart_order
        compute_apps autostart_order appinfos "${autostart_order[@]}"
        apply_autostart_order apps autostart_order "${apps[@]}"
    fi

    start_apps "$host" "$password" "${apps[@]}"

################################################################################
elif [ "$CMD" == "stop" ]; then
    function __display_help() {
        uecho "woctl stop: Arrêter une ou plusieurs instances

USAGE
    stop Application[.woa]...
    stop Application-N...
        Arrêter toutes les instances de l'application ou seulement l'instance
        spécifiée.
        Pour toutes les commandes stop, si l'application ou l'instance ne tourne
        déjà plus, aucune opération n'est effectuée. Dans le cas contraire,
        l'autoRecover est désactivé pour chacune des applications qui ont été
        arrêtées avec succès.
    stop -a
        Arrêter toutes les instances qui tournent actuellement.
    stop -A
        Forcer l'arrêt de toutes les instances configurées, même si elles ne
        semblent pas tourner pour le moment.

OPTIONS
    -s  Arrêter les applications en utilisant l'ordre inverse fourni par le
        fichier WOCONFIGURATION/AutoStart.txt
        Cette option est toujours active pour les options -a et -A
    -f  Forcer la désactivation de l'autoRecover même si l'instance ne tourne
        pas.
    -n  Ne pas désactiver l'autoRecover avant l'arrêt de l'instance."
    }

    host=
    password=
    stop_running=
    all_configured=
    apply_autostart_order=
    force_disable_autorecover=
    disable_autorecover=1
    parse_opts "${PRETTYOPTS[@]}" \
        --help '$exit_with __display_help' \
        -h:,-H:,--host: host= \
        -p:,--password: password= \
        -a '$stop_running=1; apply_autostart_order=1' \
        -A '$stop_running=1; all_configured=1; apply_autostart_order=1' \
        -s apply_autostart_order=1 \
        -f force_disable_autorecover=1 \
        -n disable_autorecover= \
        @ args -- "$@" && set -- "${args[@]}" || die "$args"

    # calculer la liste des applications puis les arrêter
    check_compute_apps_localhost "$host" "$@" || die
    wom_getApplications appinfos "" "$host" "$password"

    if [ -n "$stop_running" ]; then
        wom_getValidAndRunning valid_apps running_apps "$host" "$password" || die "$(get_error_msg $? "de charger la liste des applications")"
        
        if [ -n "$all_configured" ]; then
            # Prendre toutes les applications configurées
            array_copy apps valid_apps
            [ -n "${apps[*]}" ] || die "Aucune application configurée n'a été trouvée"
        else
            # Prendre les applications qui tournent actuellement
            array_copy apps running_apps
        fi
    else
        apps=("$@")
    fi

    compute_apps apps appinfos "${apps[@]}" || die "Impossible de trouver les applications ou frameworks spécifiés"
    if [ -n "$apply_autostart_order" ]; then
        get_autostart_order autostart_order
        compute_apps autostart_order appinfos "${autostart_order[@]}"
        apply_autostart_order -r apps autostart_order "${apps[@]}"
    fi

    stop_apps "$host" "$password" "${apps[@]}"

################################################################################
elif [ "$CMD" == "restart" ]; then
    function __display_help() {
        uecho "woctl restart: Redémarrer une ou plusieurs instances

USAGE
    restart Application[.woa]...
    restart Application-N...
        Redémarrer toutes les instances de l'application ou seulement l'instance
        spécifiée.
    restart -a
        Relancer toutes les instances qui tournent actuellement.
    restart -A
        Forcer le redémarrage de toutes les applications configurées. La
        différence avec -a est que si une instance configurée ne tournait pas,
        elle sera néanmoins démarrée.

OPTIONS
    -s  Redémarrer les applications en utilisant l'ordre fourni par le fichier
        WOCONFIGURATION/AutoStart.txt
        Cette option est toujours active pour les options -a et -A
    -n  Ne pas activer l'autoRecover après le redémarrage des applications.
    -f  Forcer le redémarrage des applications même si elles ne tournaient pas.
        Par défaut, une application n'est relancée que si elle tournait déjà. "
    }

    host=
    password=
    restart_running=
    all_configured=
    apply_autostart_order=
    enable_autorecover=1
    force_restart=
    parse_opts "${PRETTYOPTS[@]}" \
        --help '$exit_with __display_help' \
        -h:,-H:,--host: host= \
        -p:,--password: password= \
        -a '$restart_running=1; apply_autostart_order=1' \
        -A '$restart_running=1; all_configured=1; apply_autostart_order=1' \
        -s apply_autostart_order=1 \
        -n enable_autorecover= \
        -f force_restart=1 \
        @ args -- "$@" && set -- "${args[@]}" || die "$args"

    # calculer la liste des applications, les arrêter, puis les démarrer
    check_compute_apps_localhost "$host" "$@" || die
    wom_getApplications appinfos "" "$host" "$password"

    if [ -n "$restart_running" -o -n "$apply_autostart_order" ]; then
        wom_getValidAndRunning valid_apps running_apps "$host" "$password" || die "$(get_error_msg $? "de charger la liste des applications")"
        check_autostart valid_apps || die
    fi

    if [ -n "$restart_running" ]; then
        if [ -n "$all_configured" ]; then
            # Prendre toutes les applications configurées
            array_copy apps valid_apps
            force_restart=1
            [ -n "${apps[*]}" ] || die "Aucune application configurée n'a été trouvée"
        else
            # Prendre les applications qui tournent actuellement
            array_copy apps running_apps
        fi
    else
        apps=("$@")
    fi

    compute_apps apps appinfos "${apps[@]}" || die "Impossible de trouver les applications ou frameworks spécifiés"
    if [ -n "$apply_autostart_order" ]; then
        get_autostart_order autostart_order
        compute_apps autostart_order appinfos "${autostart_order[@]}"
        apply_autostart_order apps autostart_order "${apps[@]}"
    fi

    disable_autorecover=1
    force_disable_autorecover=
    stop_apps -a stopped "$host" "$password" "${apps[@]}"
    if [ -n "$force_restart" ]; then
        start_apps "$host" "$password" "${apps[@]}"
    else
        start_apps "$host" "$password" "${stopped[@]}"
    fi

################################################################################
elif [ "$CMD" == "bounce" ]; then
    function __display_help() {
        uecho "woctl bounce: Redémarrer une ou plusieurs instances en mode bounce

USAGE
    bounce Application[.woa]...
    bounce Application-N...
        Redémarrer toutes les instances de l'application ou seulement l'instance
        spécifiée, en mode bounce."
    }

    host=
    password=
    parse_opts "${PRETTYOPTS[@]}" \
        --help '$exit_with __display_help' \
        -h:,-H:,--host: host= \
        -p:,--password: password= \
        @ args -- "$@" && set -- "${args[@]}" || die "$args"

    # calculer la liste des applications puis les relancer en mode bounce
    check_compute_apps_localhost "$host" "$@" || die
    wom_getApplications appinfos "" "$host" "$password"
    compute_apps apps appinfos "$@" || die "Impossible de trouver les applications ou frameworks spécifiés"

    bounce_apps "$host" "$password" "${apps[@]}"

################################################################################
elif [ "$CMD" == "wotaskd" ]; then
    function __display_help() {
        uecho "woctl wotaskd: piloter le service wotaskd

USAGE
    wotaskd <-s|-k|-r>

OPTIONS
    -r  Redémarrer wotaskd (équivalent à -t -s)
    -t  Arrêter wotaskd
    -s  Démarrer wotaskd

Sur MacOSX, seul wotaskd est piloté. Sur linux, wotaskd et javaMonitor sont tous
les deux impactés."
    }

    stop=
    start=
    parse_opts "${PRETTYOPTS[@]}" \
        --help '$exit_with __display_help' \
        -k,-t stop=1 \
        -s start=1 \
        -r '$stop=1; start=1' \
        @ args -- "$@" && set -- "${args[@]}" || die "$args"

    case "$1" in
    s|start) start=1;;
    k|kill|t|stop) stop=1;;
    r|restart) stop=1; start=1;;
    esac
    [ -n "$stop" -o -n "$start" ] || die_with "Vous devez spécifier l'action à effectuer" __display_help

    run_as_root wotaskd ${stop:+-t} ${start:+-s}
    urequire service

    if [ -n "$stop" ]; then
        estep "Arrêt de wotaskd"
        service wotaskd stop
        [ -n "$start" ] && sleep 2
    fi
    if [ -n "$start" ]; then
        estep "Démarrage de wotaskd"
        service wotaskd start
    fi

################################################################################
elif [ "$CMD" == "javamonitor" ]; then
    function __display_help() {
        uecho "woctl javamonitor: piloter le service JavaMonitor

USAGE
    javamonitor <-s|-k|-r>

OPTIONS
    -r  Redémarrer javamonitor (équivalent à -t -s)
    -t  Arrêter javamonitor
    -s  Démarrer javamonitor

Sur MacOSX, seul javamonitor est piloté. Sur linux, wotaskd et javaMonitor sont tous
les deux impactés."
    }

    parse_opts "${PRETTYOPTS[@]}" \
        --help '$exit_with __display_help' \
        -k,-t stop=1 \
        -s start=1 \
        -r '$stop=1; start=1' \
        @ args -- "$@" && set -- "${args[@]}" || die "$args"

    case "$1" in
    s|start) start=1;;
    t|stop) stop=1;;
    r|restart) stop=1; start=1;;
    esac
    [ -n "$stop" -o -n "$start" ] || die_with "Vous devez spécifier l'action à effectuer" __display_help

    run_as_root javamonitor ${stop:+-t} ${start:+-s}
    urequire service

    if [ -n "$stop" ]; then
        estep "Arrêt de javamonitor"
        service javamonitor stop
        [ -n "$start" ] && sleep 2
    fi
    if [ -n "$start" ]; then
        estep "Démarrage de javamonitor"
        service javamonitor start
    fi

################################################################################
elif [ "$CMD" == "woservices" ]; then
    function __display_help() {
        uecho "woctl woservices: piloter les services wotaskd et javamonitor

USAGE
    woservices <-s|-k|-r>

OPTIONS
    -r  Redémarrer wotaskd et javamonitor (équivalent à -t -s)
    -t  Arrêter wotaskd et javamonitor
    -s  Démarrer wotaskd et javamonitor"
    }

    parse_opts "${PRETTYOPTS[@]}" \
        --help '$exit_with __display_help' \
        -k,-t stop=1 \
        -s start=1 \
        -r '$stop=1; start=1' \
        @ args -- "$@" && set -- "${args[@]}" || die "$args"

    case "$1" in
    s|start) start=1;;
    t|stop) stop=1;;
    r|restart) stop=1; start=1;;
    esac
    [ -n "$stop" -o -n "$start" ] || die_with "Vous devez spécifier l'action à effectuer" __display_help

    run_as_root woservices ${stop:+-t} ${start:+-s}
    urequire service

    if [ -n "$stop" ]; then
        estep "Arrêt de wotaskd et javamonitor"
        service woservices stop
        [ -n "$start" ] && sleep 2
    fi
    if [ -n "$start" ]; then
        estep "Démarrage de wotaskd et javamonitor"
        service woservices start
    fi

################################################################################
elif [ "$CMD" == "configure" ]; then
    urequire woinst
    woconf "$@"
    
################################################################################
elif [ "$CMD" == "tag" ]; then
    urequire woinst
    wotag "$@"

################################################################################
elif [ "$CMD" == "run" ]; then
    function __fixbool() {
        if [ "$1" == "-" ]; then
            echo FALSE
        elif is_yes "$1"; then
            echo TRUE
        elif is_no "$1"; then
            echo FALSE
        else
            echo "$2"
        fi
    }
    function run_filter() {
        if [ -n "$openinbrowser" ]; then
            local direct
            if is_yes "$directconnect"; then
                direct=1
            else
                direct=0
            fi
            local da="$directaction"
            if [ -n "$da" ]; then
                beginswith "$da" / || da="/$da"
                beginswith "$da" /wa || da="/wa$da"
            fi
            
            pwd="$(pwd)"
            awkrun pwd="$pwd" HOME="$HOME" da="$da" direct="$direct" openurl_path="$scriptdir/openurl" '
BEGIN {
    opened = 0
    openurl = 0
    direct = direct + 0
}
{ print; fflush() }

!direct && $0 ~ /The URL for webserver connect is:$/ {
    openurl = 1
    next
}
direct && $0 ~ /^The URL for direct connect is:$/ {
    openurl = 1
    next
}
!opened && openurl {
    url = $0
    if (da) url = url da
    cmd = openurl_path " '\''" url "'\'' &"
    print "--> " cmd
    system(cmd)
    opened = 1
    openurl = 0
    next
}
'
        else
            cat
        fi
    }
    function __display_help() {
        uecho "woctl run: lancer une application WebObjects

USAGE
    run [option] [/path/to/]Application.woa [args]

OPTIONS
    -D  Lancer l'application en mode DEBUG (par défaut)
        Utiliser -D- pour désactiver le mode DEBUG
    -S  Lancer l'application en mode DEBUG SQL
    -d  Activer le mode direct connect.

    -x  Activer remote debug
    -X  Activer remote debug w/suspend

    -o  Ouvrir un navigateur sur la page par défaut. note: le mode DEBUG *doit*
        être activé, parce que l'url à ouvrir n'est affichée qu'en mode DEBUG.
    -a=[class/]action
        Ouvrir un navigateur sur une page directe au lieu de la page par défaut
        Implique -o"
    }

    debug=true
    sqldebug=false
    directconnect=false
    remotedebug=
    remotedebug_port=8000
    remotedebug_suspend=n
    openinbrowser=
    directaction=
    parse_opts "${PRETTYOPTS[@]}" \
        --help '$exit_with __display_help' \
        -D:: '$set@ debug true' \
        -S:: '$set@ sqldebug true' \
        -d:: '$set@ directconnect true' \
        -x remotedebug=1 \
        -X '$remotedebug=1; remotedebug_suspend=y' \
        -o openinbrowser=1 \
        -a: directaction= \
        @ args -- "$@" && set -- "${args[@]}" || die "$args"

    debug="$(__fixbool "$debug" TRUE)"
    sqldebug="$(__fixbool "$sqldebug" FALSE)"
    directconnect="$(__fixbool "$directconnect" FALSE)"
    [ -n "$directaction" ] && openinbrowser=1

    appdir="$1"
    if [ -z "$1" ]; then
        appdir="$(pwd)"
        if ! endswith "$appdir" .woa; then
            die "Il faut spécifier l'application à lancer."
        fi
    fi
    
    if [ -d "$appdir" ]; then
        appdir="$(abspath "$appdir")"
        if ! endswith "$appdir" .woa; then
            die "Le nom de l'application doit se terminer par .woa"
        fi
        appscript="$appdir/$(basename "$appdir" .woa)"
    elif [ -f "$appdir" ]; then
        appscript="$appdir"
        appdir="$(dirname "$appscript")"
    else
        if ! endswith "$appdir" .woa; then
            die "Le nom de l'application doit se terminer par .woa"
        fi
        appdir="$WOAPPLICATIONS/$appdir"
        if [ ! -d "$appdir" ]; then
            die "Application non trouvée: $appdir"
        fi
        appscript="$appdir/$(basename "$appdir" .woa)"
    fi

    urequire java
    select_java 1.5 || die "Impossible de trouver une version de java 1.5"

    if [ -n "$remotedebug" ]; then
        enote "L'application peut être débuggée en mode remote sur le port $remotedebug_port"
        set -- -Xdebug "-Xrunjdwp:transport=dt_socket,address=$remotedebug_port,server=y,suspend=$remotedebug_suspend" "$@"
    fi
    cd "$appdir"
    "$appscript" -WOCachingEnabled FALSE -WODebuggingEnabled "$debug" \
        -EOAdaptorDebugEnabled "$sqldebug" \
        -WODirectConnectEnabled "$directconnect" "$@" | run_filter

################################################################################
elif [ "$CMD" == "download" ]; then
    urequire woinst # pour avoir date2version

    function process_fwk() {
        fwk="$1"
        fwkname="$(basename "$fwk")"
        if [ -d "$destdir/$fwkname" ]; then
            estep "Mise à jour de $fwkname"
            rm -rf "$destdir/$fwkname"
        else
            estep "Installation de $fwkname"
        fi
        verifix_bundle "$fwk"
        cp -a "$fwk" "$destdir"
        
        echo "$scriptdir/woctl tag -v \"$version\" -d \"$date\" -m \"$desc (framework)\" $fwkname" >>"$destdir/$versionscript"
        found_bundle=1
    }
    function process_app() {
        app="$1"
        appname="$(basename "$app")"
        if [ -d "$destdir/$appname" ]; then
            estep "Mise à jour de $appname"
            rm -rf "$destdir/$appname"
        else
            estep "Installation de $appname"
        fi
        verifix_bundle "$app"
        cp -a "$app" "$destdir"
        
        configfile="$(get_configfile "$app/Contents/Resources")"
        configname="$(basename "$configfile")"
        estep "Copie du fichier de configuration $configname"
        /bin/cp -f "$configfile" "$destdir/$(basename "$app")-$configname.orig"
        
        echo "$scriptdir/woctl tag -v \"$version\" -d \"$date\" -m \"$desc\" $appname" >>"$destdir/$versionscript"
        found_bundle=1
    }
    function __display_help() {
        uecho "woctl download: télécharger une archive d'une application ou d'un framework WebObjects

USAGE
    download [-d destdir] [url [version [date]]]

OPTIONS
    date est obligatoire et vaut par défaut la date du jour.
    S'il n'y a pas de numéro de version, utiliser '-'.

    -d destdir
        Répertoire de base pour la sauvegarde des fichiers. Par défaut,
        utiliser le répertoire courant.
    -n name
        Nom du produit. Par défaut, prendre \$(basename \"\$destdir\")
        Après le téléchargement, le script prepare_\${name}.sh, s'il existe, est
        exécuté dans le répertoire destdir. Cela permet d'effectuer d'autres
        préparations sur le bundle téléchargé, comme la configuration de
        paramètres par défaut, etc.
    -f  désactiver le cache lors du téléchargement.
    -m desc
        Spécifier une description."
    }

    destdir=
    name=
    nocache=
    desc=
    parse_opts "${PRETTYOPTS[@]}" \
        --help '$exit_with __display_help' \
        -d:,--destdir: destdir= \
        -n:,--name: name= \
        -f,--nocache nocache=1 \
        -m:,--desc: desc= \
        @ args -- "$@" && set -- "${args[@]}" || die "$args"

    [ -z "$destdir" ] && destdir=.
    destdir="$(abspath "$destdir")"
    [ -z "$name" ] && name="$(basename "$destdir")"

    URLPOS="${URLPOS:-1}"
    VERSIONPOS="${VERSIONPOS:-2}"
    DATEPOS="${DATEPOS:-3}"

    url=; version=; date=
    [ "$URLPOS" != "-" ] && eval "url=\"\${$URLPOS:-\$url}\""
    [ "$VERSIONPOS" != "-" ] && eval "version=\"\${$VERSIONPOS:-\$version}\""
    [ "$DATEPOS" != "-" ] && eval "date=\"\${$DATEPOS:-\$date}\""
    
    # demander l'url, la version, la date
    readopt=
    [ -n "$url" ] && readopt=-i
    read_value $readopt "Entrez l'url à télécharger" url "$url"

    readopt=
    [ -n "$version" ] && readopt=-i
    read_value $readopt "Entrez le numéro de version (vide s'il n'y a que la date de release)" version "$version" N
    
    readopt=
    [ -n "$date" ] && readopt=-i
    [ -z "$date" ] && date="$(date +%d/%m/%Y)"
    read_value $readopt "Entrez la date de release" date "$date"

    if [ -z "$version" ]; then
        fsversion="$(date2version "$date")"
        version=-
    else
        fsversion="$version"
    fi

    dldir="$destdir/$fsversion"
    preparescript="prepare_$name.sh"
    versionscript="version-$fsversion.sh"

    # Télécharger l'archive dans un répertoire temporaire
    ac_set_tmpdir tmpdir
    curdir="$(pwd)"
    cd "$tmpdir"
    wget -nv ${nocache:+--cache=off} "$url" || die
    cd "$curdir"

    # Trouver son nom
    array_lsfiles dlfiles "$tmpdir"
    dlfile="${dlfiles[0]}"
    dlname="$(basename "$dlfile")"
    bname=
    if endswith "$dlfile" .zip || endswith "$dlfile" .jar || endswith "$dlfile" .war || endswith "$dlfile" .ear; then
        bname="${dlname%.*}"
    elif endswith "$dlfile" .tgz; then
        bname="${dlname%.tgz}"
    elif endswith "$dlfile" .tar.gz; then
        bname="${dlname%.tar.gz}"
    elif endswith "$dlfile" .tbz2; then
        bname="${dlname%.tbz2}"
    elif endswith "$dlfile" .tar.bz2; then
        bname="${dlname%.tar.bz2}"
    else
        mimetype="$(file -b -i "$dlfile")"
        type="$(file -b "$dlfile")"
        if beginswith "$mimetype" application/x-zip; then
            mv "$dlfile" "$dlfile.zip"
            bname="$dlfile"
            dlfile="$dlfile.zip"
        elif beginswith "$type" Zip; then
            mv "$dlfile" "$dlfile.zip"
            bname="$dlfile"
            dlfile="$dlfile.zip"
        elif beginswith "$mimetype" application/x-gzip; then
            mv "$dlfile" "$dlfile.tgz"
            bname="$dlfile"
            dlfile="$dlfile.tgz"
        elif beginswith "$type" gzip; then
            mv "$dlfile" "$dlfile.tgz"
            bname="$dlfile"
            dlfile="$dlfile.tgz"
        elif beginswith "$mimetype" application/x-bzip2; then
            mv "$dlfile" "$dlfile.tbz2"
            bname="$dlfile"
            dlfile="$dlfile.tbz2"
        elif beginswith "$type" bzip2; then
            mv "$dlfile" "$dlfile.tbz2"
            bname="$dlfile"
            dlfile="$dlfile.tbz2"
        else
            mkdir -p "$dldir"
            /bin/mv -f "$dlfile" "$dldir"
            die "Archive de format inconnu: $dlfile"
        fi
        dlname="$(basename "$dlfile")"
        bname="$(basename "$bname")"
    fi

    # Le copier dans le répertoire de destination
    mkdir -p "$dldir"
    /bin/cp -f "$dlfile" "$dldir"

    # Décompresser l'archive
    cd "$tmpdir"
    extract_archive "$dlname"

    # Copier les fichiers et générer le script de configuration
    echo "#!/bin/bash
" >"$destdir/$versionscript"
    chmod +x "$destdir/$versionscript"

    found_bundle=

    array_from_lines fwks "$(find . -path ./__MACOSX -prune -o -name "*.framework" -print)"
    for fwk in "${fwks[@]}"; do
        process_fwk "$fwk"
    done

    array_from_lines apps "$(find . -path ./__MACOSX -prune -o -name "*.woa" -print)"
    for app in "${apps[@]}"; do
        process_app "$app"
    done

    # Si pas trouvé de bundle, le fichier lui-même est peut-être un bundle en entier
    if [ -z "$found_bundle" ]; then
        if endswith "$bname" .woa || endswith "$bname" .framework; then
            # ne garder bname que s'il se termine par .woa ou .framework
            rm -rf "$bname"
            mkdir "$bname"
            cd "$bname"
            extract_archive "../$dlname"
            cd "$tmpdir"
            
            if endswith "$bname" .framework; then
                process_fwk "$bname"
            elif endswith "$bname" .woa; then
                process_app "$bname"
            fi
        fi
    fi

    # tester la presence de fichiers SQL
    if [ -n "$(find . -iname "*.sql")" ]; then
        ewarn "Il y a des fichiers SQL dans cette archive:"
        find . -iname "*.sql" | sed -e 's,^./,,g'
    fi

    # configuration
    cd "$destdir"
    estep "Configuration de la version et des paramètres"
    "./$versionscript"
    [ -x "$preparescript" ] && "./$preparescript"

################################################################################
else
    die "$CMD: commande inconnue"
fi