#!/bin/sh

alterator_api_version=1
po_domain="alterator-nagios-secondary"
po_charset="UTF-8"

. alterator-sh-functions
. shell-config
. alterator-service-functions

NAGIOSCONFDIR=/etc/nagios
OBJECTDIR="$NAGIOSCONFDIR/objects"
TEMPLATEDIR="$NAGIOSCONFDIR/templates"
EXTINFODIR="$NAGIOSCONFDIR/extinfo"
SECONDARYDIR="$EXTINFODIR/secondary"

BASE_SERVICE='generic-service'

list_file_objects() {
    local file="$1"
    local def_type="$2"
    local def_name="$3"
    local def_desc="$4"

    sed -n -e "
/^[[:space:]]*define[[:space:]]\\+$def_type[[:space:]]*{/,/}/ {
    /^[[:space:]]*define[[:space:]]\\+$def_type[[:space:]]*{/ {
        z; H; d;
    }
    /^[[:space:]]*register[[:space:]]\\+0\\([[:space:]].*\\)\$/ {
        s/^.*\$/SKIP/;
        h;
        d;
    }
    /^[[:space:]]*$def_name[[:space:]]/ {
        s/^[[:space:]]*$def_name[[:space:]]\\+\\([^#]*\\).*\$/N:\\1/;
        s/[[:space:]]*\$//;
        H;
        x; s/^\\(.*\\)\\n\\(N:[^\\n]*\\)\$/\\1\\t\\2/; x;
        d;
    }
    /^[[:space:]]*$def_desc[[:space:]]/ {
        s/^[[:space:]]*$def_desc[[:space:]]\\+\\([^#]*\\).*\$/A:\\1/;
        s/[[:space:]]*\$//;
        H;
        x; s/^\\(.*\\)\\n\\(A:[^\\n]*\\)\$/\\1\\t\\2/; x;
        d;
    }
    /}/ {
        g;
        /^[[:space:]]*\$/ { z; g; d; }
        /^SKIP/ { z; g; d; }
        /^\\n\\tN:[^\\t]*\\tA:[^\\t]*\$/ {
            s/^\\n\\tN:\\([^\\t]*\\)\\tA:\\([^\\t]*\\)\$/\\1\\t\\2/;
            p;
        }
        /^\\n\\tA:[^\\t]*\\tN:[^\\t]*\$/ {
            s/^\\n\\tA:\\([^\\t]*\\)\\tN:\\([^\\t]*\\)\$/\\2\\t\\1/;
            p;
        }
        /^\\n\\tN:[^\\t]*\$/ {
            s/^\\n\\tN:\\([^\\t]*\\)\$/\\1\\t\\1/;
            p;
        }
        z; h; d;
    }
}" "$file"
}

list_hostgroups() {
    find "$OBJECTDIR" "$TEMPLATEDIR" -name '*.cfg' 2>/dev/null | \
        while read f; do
            list_file_objects "$f" 'hostgroup' 'hostgroup_name' 'alias'
        done | \
            sort -u
}

list_hosts() {
    find "$OBJECTDIR" "$TEMPLATEDIR" -name '*.cfg' 2>/dev/null | \
        while read f; do
            list_file_objects "$f" 'host' 'host_name' 'alias'
        done | \
            sort -u
}

list_services() {
    find "$OBJECTDIR" "$TEMPLATEDIR" -name '*.cfg' 2>/dev/null | \
        while read f; do
            list_file_objects "$f" 'service' 'name' 'service_description'
        done | \
            sort -u
}

list_secondary_services() {
    find "$SECONDARYDIR" -name '*.cfg' 2>/dev/null | \
        while read f; do
            list_file_objects "$f" 'service' 'name' 'service_description'
        done | \
            sort -u
}

list_to_items() {
    while read key val; do
        if [ "$val" != "$key" ]; then
            write_enum_item "$key" "$key ($val)"
        else
            write_enum_item "$key" "$key"
        fi
    done
}

write_command_args() {
    while [ $# -gt 0 ]; do
        echo -n '!'
        echo -n "$1"
        shift
    done
    echo
}

write_secondary_service() {
    local name="$1"; shift
    local desc="$1"; shift
    local hosts="$1"; shift
    local hostgroups="$1"; shift
    local check="$1"; shift

    mkdir -p "$SECONDARYDIR"
    cat >"$SECONDARYDIR/$name.cfg" <<EOF
define service {
	name			$name
EOF

    if [ -n "$hosts" ]; then
        cat >>"$SECONDARYDIR/$name.cfg" <<EOF
	host_name		$hosts
EOF
    fi

    if [ -n "$hostgroups" ]; then
        cat >>"$SECONDARYDIR/$name.cfg" <<EOF
	hostgroup_name		$hostgroups
EOF
    fi

    cat >>"$SECONDARYDIR/$name.cfg" <<EOF
	use			$BASE_SERVICE
	service_description	$desc
	check_command		$check$(write_command_args "$@")
}
EOF
}

delete_secondary_service() {
    local name="$1"

    rm -f "$SECONDARYDIR/$name.cfg"
}

servname_to_desc() {
    local servname="$1"

    (
        list_services
        list_secondary_services
    ) | \
        sed -n -e "/^$servname\\t/ { s/^$servname\\t//; p; q0 }"
}

desc_to_servname() {
    local desc="$1"

    (
        list_services
        list_secondary_services
    ) | \
        sed -n -e "/\\t$desc\$/ { s/\\t$desc\$//; p; q0 }"
}

write_service_alerts() {
    local name="$1"
    local desc="$2"
    local hosts="$3"
    local hostgroups="$4"
    local servname="$5"
    local state="$6"
    local interval="$7"
    local wtimes="$8"
    local ctimes="$9"

    if [ -z "$name" ]; then
        write_error "$(_ 'Empty service name is not allowed!')"
        return 1
    fi

    if [ -z "$servname" ]; then
        write_error "$(_ 'Name of the target service should not be empty!')"
        return 1
    fi

    case "$state" in
        warning|critical)
            ;;
        *)
            write_error "$(printf "$(_ "Unexpected service state value: %s")" "$state")"
            return 1
            ;;
    esac

    write_secondary_service "$name" "$desc" "$hosts" "$hostgroups" \
        check-service-alerts "$(servname_to_desc "$servname")" \
                             "$(echo "$state" | tr '[[:lower:]]' '[[:upper:]]')" \
                             "$interval" "$wtimes" "$ctimes"
}

read_config() {
    local file="$1"

    if [ -e "$file" ]; then
        sed -n -e '
/^[[:space:]]*define[[:space:]]\+[^[:space:]]\+[[:space:]]*{/,/}/ {
    /^[[:space:]]*define[[:space:]]\+[^[:space:]]\+[[:space:]]*{/ {
        s/^[[:space:]]*define[[:space:]]\+\([^[:space:]]\+\)[[:space:]]*{/objtype\t\1/;
        s/[[:space:]]*$//;
        H;
    }
    /}/ {
        g;
        s/^\n//;
        p;
        q0
    }
    /^[[:space:]]*[^[:space:]]\+[[:space:]]/ {
        s/^[[:space:]]*\([^[:space:]]\+\)[[:space:]]\+\([^#]*\).*$/\1\t\2/;
        s/[[:space:]]*$//;
        H;
    }
}
$ q1' "$file"
    fi
}

unquote() {
    local val="$1"
    val="${val#'}"
    val="${val%'}"
    val="${val#\"}"
    val="${val%\"}"
    echo "$val"
}

# check-service-alerts!servname!state!interval!wtimes!ctimes
read_service_alerts() {
    echo "$*" | (
        IFS='!'
        read cmd servname state interval wtimes ctimes

        if [ "$cmd" != 'check-service-alerts' ]; then
            write_error "$(printf "$(_ "Unexpected service alert check command: %s")" "$cmd")"
            exit 1
        fi

        write_string_param 'servname' "$(desc_to_servname "$servname")"
        write_string_param 'state' "$(echo "$state" | tr '[[:upper:]]' '[[:lower:]]')"
        write_string_param 'interval' "$interval"
        write_string_param 'wtimes' "$wtimes"
        write_string_param 'ctimes' "$ctimes"
    )
}

read_secondary_service() {
    local name="$1"

    read_config "$SECONDARYDIR/$name.cfg" | \
        while read key val; do
            case "$key" in
                objtype)
                    if [ "$val" != 'service' ]; then
                        write_error "$(printf "$(_ "Unexpected object type: %s")" "$val")"
                        return 1
                    fi
                    ;;
                check_command)
                    cmd="$(echo "$val" | sed -e 's/^\([^!]\+\).*$/\1/')"
                    case "$cmd" in
                        check-service-alerts)
                            write_string_param 'checktype' 'service-alerts'
                            read_service_alerts "$val"
                            ;;
                        *)
                            write_error "$(printf "$(_ "Unexpected check command: %s")" "$val")"
                            return 2
                            ;;
                    esac
                    ;;
                service_description)
                    write_string_param 'desc' "$val"
                    ;;
                host_name|hostgroup_name)
                    write_string_param "${key%_name}s" "$(echo "$val" | sed -e 's/,[[:space:]]*/;/g')"
                    ;;
                *)
                    write_string_param "$key" "$val"
                    ;;
            esac
        done
}

reload_nagios() {
    service_control nagios condreload
}

### message loop

on_message(){
    case "$in_action" in
        type)
            write_type_item 'name' 'keyword'
            write_type_item 'host' 'keyword'
            write_type_item 'checktype' 'keyword'
            write_type_item 'servname' 'keyword'
            write_type_item 'state' 'keyword'
            write_type_item 'interval' 'integer'
            write_type_item 'wtimes' 'integer'
            write_type_item 'ctimes' 'integer'
            ;;
        list)
            case "$in__objects" in
                hosts)
                    list_hosts | list_to_items
                    ;;
                hostgroups)
                    list_hostgroups | list_to_items
                    ;;
                services)
                    list_services | list_to_items
                    ;;
                secondary)
                    list_secondary_services | list_to_items
                    ;;
                checktypes)
                    write_enum_item 'service-alerts' "$(_ 'Service alerts')"
                    ;;
                states)
                    write_enum_item 'warning' "$(_ 'WARNING')"
                    write_enum_item 'critical' "$(_ 'CRITICAL')"
                    ;;
                *)
                    write_error "$(printf "$(_ "Unexpected object: %s")" "$in__objects")"
                    ;;
            esac
            ;;
        read)
            case "$in__objects" in
                secondary/*)
                    read_secondary_service "${in__objects#secondary/}"
                    ;;
                *)
                    write_error "$(printf "$(_ "Unexpected object: %s")" "$in__objects")"
                    ;;
            esac
            ;;
        write)
            case "$in__objects" in
                secondary/*)
                    case "$in_checktype" in
                        service-alerts)
                            write_service_alerts "${in__objects#secondary/}" \
                                                 "$in_desc" \
                                                 "$in_hosts" \
                                                 "$in_hostgroups" \
                                                 "$in_servname" \
                                                 "${in_state:-critical}" \
                                                 "${in_interval:-0}" \
                                                 "${in_wtimes:-0}" \
                                                 "${in_ctimes:-0}"
                            reload_nagios
                            ;;
                        *)
                            write_error "$(printf "$(_ "Unexpected check type: %s")" "$in_checktype")"
                            ;;
                    esac
                    ;;
                *)
                    write_error "$(printf "$(_ "Unexpected object: %s")" "$in__objects")"
                    ;;
            esac
            ;;
        delete)
            case "$in__objects" in
                secondary/*)
                    delete_secondary_service "${in__objects#secondary/}"
                    reload_nagios
                    ;;
                *)
                    write_error "$(printf "$(_ "Unexpected object: %s")" "$in__objects")"
                    ;;
            esac
            ;;
        *)
            write_error "$(printf "$(_ "Unexpected action: %s")" "$in_action")"
            ;;
    esac
}

message_loop
