#!/bin/sh -e
# $Id: sisyphus_link_groups,v 1.2 2005/05/20 16:51:04 legion Exp $

. /etc/sisyphus/config
. /etc/sisyphus/functions

cd "$PREFIX"

export LC_ALL=C LANG=C LANGUAGE=C

action=
bts_user=
users=
packages=
interactive=
verbose=

tab_char="$(printf \\t)"
groups_file='files/list.groups'

Usage() {
    [ "$1" = 0 ] || exec >&2
    cat << EOF
Usage: $PROG [options] <user> [<user> ...]

Options:
    -a, --add                 add users to list;
    -A, --add-group           add new users group;
    -d, --del                 remove users from the lists;
    -D, --del-group           remove users group;
    -r, --replace             replace all users;
    -g, --group=GROUP         change user list for GROUP;
    -b, --bts=NAME            set user as BTS user;
    -i, --interactive         read the package names from the stdin.
    -h, --help                show this message

EOF
    [ -n "$1" ] && exit "$1" || exit
}

quote() {
    printf %s "$*" | sed -e 's,[-.,*/\`\"$],\\&,g' || return 1
}

cleanup_args() {
    printf %s "$*"
}

add_owner() {
    local grp name owners owners_old ownerslist
    grp="$1" && shift || Fatal "argument 'group' required"
    grp="${grp#@}"
    
    owners_old="$(printf %s "@$grp" | join -t"$tab_char" -o 2.2 - "$groups_file" | tr -d \\t)"
    [ -n "$owners_old" ] || 
	{ Info "Error: can't find '$grp' at list"; return 1; }

    owners_old=" $owners_old "
    owners=
    for name in $users; do
        [ "${owners_old#* $name }" = "$owners_old" ] || 
	    { Message "$name already in lists"; continue; }
        owners="$name $owners"
    done
    [ -n "$owners" ] || { Info "Error: nothing to add"; return 1; } 

    ownerslist="$(cleanup_args $owners_old $owners)"
    subst "s,^@$grp[[:space:]].*$,@$grp\t$ownerslist," "$groups_file"
    [ -z "$verbose" ] || Message "User added: @$grp = $ownerslist"
}

del_owner() {
    local grp n new_owners o owners 
    grp="$1" && shift || Fatal "argument 'group' required"
    grp="${grp#@}"

    owners="$(printf %s "@$grp" | join -t"$tab_char" -o 2.2 - "$groups_file" | tr -d '\t')"
    [ -n "$owners" ] || Message "Owners not found for '$owners'"

    new_owners=
    for o in $owners; do
	[ "${users#* $o }" = "$users" ] || continue
	new_owners="$new_owners $o"
    done
    new_owners="$(cleanup_args $new_owners)"
    [ -n "$new_owners" ] || { Info "Cannot remove all owners: $users"; return 1; }
    subst "s,^@$grp[[:space:]].*$,@$grp\t$new_owners," "$groups_file"
    [ -z "$verbose" ] || Message "User removed: @$grp = $new_owners"
}

bts_owner() {
    local grp new_owners o owners
    grp="$1" && shift || Fatal "argument 'group' required"
    grp="${grp#@}"

    [ -n "$bts_name" ] || { Info "Error: nothing to do"; return 1; } 

    owners="$(printf %s "@$grp" | join -t"$tab_char" -o 2.2 - "$groups_file" | tr -d '\t')"
    [ -n "$owners" ] || 
	{ Info "Error: can't find grp at the lists: $grp"; return 1; }

    new_owners=
    for o in $owners; do
	[ "$o" != "$bts_name" ] || continue
	new_owners="$new_owners $o"
    done
    new_owners="$(cleanup_args $new_owners)"
    if [ -z "$owners" ]; then
	subst "s,^@$grp[[:space:]].*$,@$grp\t$new_owners," "$groups_file"
	[ -z "$verbose" ] || Message "BTS user changed: @$grp = $new_owners"
    fi
}

replace_owner() {
    local grp owners
    grp="$1" && shift || Fatal "argument 'grp' required"
    grp="${grp#@}"

    [ -n "$users" ] || { Info "Error: nothing to do"; return 1; } 
    owners="$(cleanup_args $users)"
    subst "s,^@$grp[[:space:]].*$,@$grp\t$owners," "$groups_file"
    [ -z "$verbose" ] || Message "User replaced: @$grp = $owners"
}

group_exist() {
    local g="$1" && shift
    g="${g#@}"
    [ "$(grep "^@$g[[:space:]]" "$groups_file" | wc -l)" = 1 ] || 
	{ Info "Error: group not found: $g"; return 1; }
    return 0
}

del_group() {
    local g="$1" && shift
    g="${g#@}"
    subst '\,@$g,d' "$groups_file"
    [ -z "$verbose" ] || Message "Group has been removed: @$grp"
}

add_group() {
    local g="$1" && shift
    g="${g#@}"

    if group_exist "$g"; then
	Info "Warning: group already exist1: $g"
	return 0
    fi

    [ -n "$users" ] || 
	{ Info "Error: nothing to do"; return 1; } 
    users="$(cleanup_args $users)"
    printf '%s\t%s\n' "@$g" "$users" >> "$groups_file"
    [ -z "$verbose" ] || Message "New group created: @$g = $users"
    sort -u -o "$groups_file" "$groups_file"
}

TEMP=`getopt -n $PROG -o a,A,b:,d,D,g:,h,i,r,v -l add,add-group,bts:,del,del-group,group:,help,interactive,replace,verbose -- "$@"` || Usage
eval set -- "$TEMP"

while :; do
    case $1 in
	-a| --add) action=add
	    ;;
	-A| --add-group) action=addgrp
	    ;;
	-b| --bts) shift
	    [ -z "$1" ] || { bts_name="$1"; action=bts; }
	    ;;
	-d| --del) action=del
	    ;;
	-D| --del-group) action=delgrp
	    ;;
        -g| --group) shift
            [ -z "$1" ] || groups="$1"
            ;;
	-h| --help) Usage 0
	    ;;
        -i| --interactive) interactive=1
            ;;
	-r| --replace) action=replace
	    ;;
	-v| --verbose) verbose=-v
	    ;;
	--) shift; break
	    ;;
	*) Fatal "unrecognized option: $1"
	    ;;
    esac
    shift
done

# At least one argument, please.
if ! [ "$#" -ge 1 ]; then
    Info "at least one argument is required."
    Usage
fi
users=" $@ "

if [ -n "$interactive" ]; then
    arg=
    while read arg; do
        groups="$groups $arg"
    done
fi
[ -n "$groups" ] || Usage 1

sort -u -o "$groups_file" "$groups_file"

for g in $(quote "$groups"); do
    case $action in
	add)
	    group_exist "$g" || continue
	    add_owner "$g" 
	    ;;
	del)
	    group_exist "$g" || continue
	    del_owner "$g" 
	    ;;
	bts)
	    group_exist "$g" || continue
	    bts_owner "$g" 
	    ;;
	replace) 
	    group_exist "$g" || continue
	    replace_owner "$g" 
	    ;;
	delgrp)
	    group_exist "$g" || continue
	    del_group "$g" 
	    ;;
	addgrp)
	    add_group "$g"
	    ;;
    esac
done
