#!/bin/sh -f

alterator_api_version=1
po_domain="alterator-ldap-groups"

# delimeters
rdelim='[[:space:]]\+'
wdelim=' '


cache_dir="/var/cache/alterator/ldap-groups"
default_groups="cdwriter cdrom audio proc radio camera floppy xgrp scanner uucp users"

. alterator-sh-functions
. alterator-openldap-functions
. shell-quote

#turn off auto expansion
set -f

### cache

reset_cache()
{
  rm -rf -- "$cache_dir"
  mkdir -p -- "$cache_dir"
}

### member
member_list()
{
    local group="$1";shift
    local member_in_file="$cache_dir/member-in-$group"
    local member_out_file="$cache_dir/member-out-$group"

    case "$mode" in
    local)
	grep "^$group:" /etc/group |cut -f4 -d':'|tr ',' '\n'|sort >"$member_in_file"
	
	getent passwd | cut -f1 -d ':'| sort|
	while read user;do
	  fgrep -wqs "$user" "$member_in_file" || echo "$user"
	done>"$member_out_file"
    ;;
    ldap)
    ldap-getent group "$group" memberUid|sort|
	sed -e 's/,[[:blank:]]*/\n/g'>"$member_in_file"

    ldap-getent passwd '*' uid|sort|
	while read user;do
	  fgrep -wqs "$user" "$member_in_file" || echo "$user"
	done>"$member_out_file"
    ;;
    *);;
    esac
}

member_list_in()
{
  local group="$1";shift
  local member_in_file="$cache_dir/member-in-$group"
  local member_out_file="$cache_dir/member-out-$group"

  [ -f "$member_in_file" -a -f "$member_out_file" ] || member_list "$group"

  cat "$member_in_file"
}

member_list_out()
{
  local group="$1";shift
  local member_in_file="$cache_dir/member-in-$group"
  local member_out_file="$cache_dir/member-out-$group"

  [ -f "$member_in_file" -a -f "$member_out_file" ] || member_list "$group"

  cat "$member_out_file"
}

member_add()
{
  local group="$1";shift
  local user="$1";shift
  local member_in_file="$cache_dir/member-in-$group"
  local member_out_file="$cache_dir/member-out-$group"

  [ -f "$member_in_file" -a -f "$member_out_file" ] || member_list "$group"
  echo "$user"|tr ';' '\n'|
  while read usr; do
    file_list_add "$member_in_file" "$usr"
    file_list_del "$member_out_file" "$usr"
  done
}

member_del()
{
  local group="$1";shift
  local user="$1";shift
  local member_in_file="$cache_dir/member-in-$group"
  local member_out_file="$cache_dir/member-out-$group"

  [ -f "$member_in_file" -a -f "$member_out_file" ] || member_list "$group"
  echo "$user"|tr ';' '\n'|
  while read usr; do
    file_list_add "$member_out_file" "$usr"
    file_list_del "$member_in_file" "$usr"
  done
}

member_reset()
{
  local group="$1";shift
  local member_in_file="$cache_dir/member-in-$group"
  local member_out_file="$cache_dir/member-out-$group"

  rm -f -- "$member_in_file" "$member_out_file"
}

member_commit()
{
  local group="$1";shift
  local member_in_file="$cache_dir/member-in-$group"
  local member_out_file="$cache_dir/member-out-$group"

  [ -f "$member_in_file" -a -f "$member_out_file" ] || member_list "$group"
  case "$mode" in
  local)
    userlist=$(cat $member_in_file| sed -e '/^$/d'|tr ';\n' ','|sed -e 's/,$//')
    [ -n $userlist ] \
    && gpasswd -M "$userlist" "$group"\
    || gpasswd -M "" "$group"
  ;;
  ldap)
  if [ -s "$member_in_file" ]; then
    sed 's/.*/memberUid:&/' "$member_in_file"|ldap-groupmod replace "$group" > /dev/null
  else
    printf 'memberUid:\n'|ldap-groupmod replace "$group" > /dev/null
  fi
  ;;
  *);;
  esac
  
  member_reset "$group"
}

### e-mail

email_list()
{
  local user="$1";shift
  local email_file="$cache_dir/email-$user"
  case "$mode" in
  local);;
  ldap)
    if [ -f "$email_file" ];then
	cat "$email_file"
    else
	ldap-getent group "$user" mail|
	    sed -e 's/,[[:blank:]]*/\n/g'|
	    tee "$email_file"
    fi
  ;;
  *);;
  esac
}

email_add()
{
  local user="$1";shift
  local email="$1";shift
  local email_file="$cache_dir/email-$user"

  [ -f "$email_file" ] || email_list >/dev/null
  file_list_add "$email_file" "$email"
}

email_del()
{
  local user="$1";shift
  local email="$1";shift
  local email_file="$cache_dir/email-$user"

  [ -f "$email_file" ] || email_list >/dev/null
  file_list_del "$email_file" "$email"
}

email_reset()
{
  local user="$1";shift
  local email_file="$cache_dir/email-$user"

  rm -f -- "$email_file"
}

email_commit()
{
  local user="$1";shift
  local email_file="$cache_dir/email-$user"

  [ -f "$email_file" ] || return 0

  if [ -s "$email_file" ]; then
	sed 's/.*/mail:&/' "$email_file"|ldap-groupmod replace "$user" > /dev/null
  else
	printf 'mail:\n'|ldap-groupmod replace
  fi
  email_reset "$user"
}

### group
local_groups(){
	getent group |cut -f1 -d ':' |sort|
	while read name; do
            local is_def=""
            echo "$default_groups" | fgrep -wqs "$name" && is_def="(*) "
        	write_enum_item "$name" "$name $is_def"
        done

}

ldap_groups(){
        ldap-getent group '*' cn|sort|
        while read name; do
            local is_def=""
            echo "$default_groups" | fgrep -wqs "$name" && is_def="(*) "
        	write_enum_item "$name" "$name $is_def (L)"
        done
}

list_groups(){
    case "$mode" in
    local)  
	local_groups 
    ;;
    ldap)
#	local_groups 
	ldap_groups
    ;;
    *);;
    esac
}

group_new()
{
    local r="$(ldap-groupadd "$1" 2>&1)"
    [ -n "$r" ] && write_error "$r" && return 1
    :
}

group_delete()
{
    local r="$(ldap-groupdel "$1" 2>&1)"
    [ -n "$r" ] && write_error "$r" && return 1
    :
}

check_mode(){
	[ -n "$mode" ] || set_dn_conf
        write_string_param mode "$mode"
        write_string_param host "$host"
        write_string_param base "$base"
        write_string_param rootdn "$rootdn"
        write_string_param rootpw "$rootpw"
        write_string_param bind_info "$bind_info"
}

set_dn_conf()
{
    local data="$(/usr/sbin/system-auth status)"
    mode="$(echo "$data"|cut -f1 -d' ')"

    case "$mode" in
        local)
        host="localhost"
        base="tcb"
        rootdn="root"
        rootpw="*********"
        bind_info="present"
        export mode host base rootdn rootpw bind_info
        ;;
        ldap)
            base="$(echo "$data"|cut -f2 -d' ')"
            urihost="$(echo "$data"|cut -f3 -d' ')"
            host=$(echo "$urihost"|sed -e 's/lda.*\/\///i')
            case "$host" in
                localhost|127.0.0.1)
                DN_CONF=$(ldap-dn find "$base")
                rootdn=$(egrep "rootdn" "$DN_CONF"|cut -f2 -d' '|tr -d '"')
                rootpw="-w $(egrep "rootpw" "$DN_CONF"|cut -f2 -d' ')"
                method=$(echo "$rootpw"|sed -n -e "s/^.*{\([^}]*\)}.*$/\1/p")
		if [ -n "$method" ]; then
		    bind_info="encoded"
		else
		    bind_info="present"
		fi
                export DN_CONF
                export mode host base rootdn rootpw bind_info
                ;;
                *)
                ;;
            esac
        ;;
        krb5)
            dn="$(echo "$data"|cut -f2 -d' ')"
            dn_2_host "$dn"
            DN_CONF="$(/usr/sbin/ldap-dn find "$dn")"
            export ENABLE_KRB="yes"
            export DN_CONF
            base_rootdn_rootpw
        ;;
        *)
        ;;
    esac
}

set_new_source(){
    case "$in_newmode" in
	local)
	    mode="local"
	    export mode
	;;
	ldap)
	    host="$in_host"
	    base="$in_new_rem_base"
	    DN_CONF="remote"
	    mode="ldap"
	    bind_info="encoded"
	    export DN_CONF mode host base rootdn rootpw bind_info
	;;
	localldap)
	    mode="ldap"
	    host="localhost"
	    base="$in_new_base"
	    DN_CONF=$(ldap-dn find "$base")
	    rootdn=$(egrep "rootdn" "$DN_CONF"|cut -f2 -d' '|tr -d '"')
	    rootpw="-w $(egrep "rootpw" "$DN_CONF"|cut -f2 -d' ')"
	    method=$(echo "$rootpw"|sed -n -e "s/^.*{\([^}]*\)}.*$/\1/p")
	    if [ -n "$method" ]; then
		bind_info="encoded"
	    else
		bind_info="present"
	    fi
	    export DN_CONF mode host base rootdn rootpw bind_info
	;;
	system)
	    set_dn_conf
	;;
	*)
	;;
    esac
}

list_bases(){
    ldapsearch -x -H "ldap://${in_rem_host:-127.0.0.1}" -LLL -b "" -s base namingContexts \
	| grep naming | cut -f2 -d ' '| \
      while read base_dn ; do
        write_enum_item "$base_dn" "$base_dn"
      done 2>/dev/null
}

set_new_bind(){
    mode="$in_mode"
    base="$in_base"
    host="$in_host"
    rootdn="$in_rootdn"
    rootpw="-w $in_rootpw"
    bind_info="$in_bind_info"
    DN_CONF="remote"

    export DN_CONF mode host base rootdn rootpw bind_info

}

set_dn_conf
reset_cache

on_message()
{
	case "$in_action" in
	type)
	    write_type_item	new_group	ldap-group-name
	    write_type_item	new_email	e-mail
	    ;;
	list)
	    case "$in__objects" in
            mode)
        	check_mode
            ;;
            bases)
		list_bases
	    ;;
            *)
        	list_groups
            ;;
            esac
	    
	;;
	delete)
	    [ -n "$in_group" ] || return
	    group_delete "$in_group"
	    ;;
	new)
	    case "$in__objects" in
	    source)
		set_new_source
	    ;;
    	    *)
	    [ -n "$in_new_group" ] || return
	    group_new "$in_new_group" || return
	    ;;
	    esac
	    ;;
	member_list_in)
	    [ -n "$in_group" ] || return
	    member_list_in "$in_group"|write_enum
	    ;;
	member_list_out)
	    [ -n "$in_group" ] || return
	    member_list_out "$in_group"|write_enum
	    ;;
	member_add)
	    [ -n "$in_group" -a -n "$in_member_out" ] || return
	    member_add "$in_group" "$in_member_out"
	    ;;
	member_del)
	    [ -n "$in_group" -a -n "$in_member_in" ] || return
	    member_del "$in_group" "$in_member_in"
	    ;;
	member_commit)
	    [ -n "$in_group" ] || return
	    member_commit "$in_group"
	    ;;
	member_reset)
	    [ -n "$in_group" ] || return
	    member_reset "$in_group"
	    ;;
	email_list)
	    [ -n "$in_group" ] || return
	    email_list "$in_group" |write_enum
	    ;;
	email_add)
	    [ -n "$in_group" -a -n "$in_new_email" ] || return
	    email_add "$in_group" "$in_new_email"
	    ;;
	email_del)
	    [ -n "$in_group" -a -n "$in_email" ] || return
	    email_del "$in_group" "$in_email"
	    ;;
	email_commit)
	    [ -n "$in_group" ] || return
	    email_commit "$in_group"
	    ;;
	email_reset)
	    [ -n "$in_group" ] || return
	    email_reset "$in_group"
	    ;;
	set_bind)
	    [ -n "$in_mode" -a -n "$in_base" -a -n "$in_host"  -a -n "$in_rootdn" -a -n "$in_rootpw" ] && set_new_bind
	    ;;
	esac
}

message_loop
