#!/bin/ash
# Fatdog64 User Manager
# Copyright (C) James Budiono 2012, 2017
#
# License: GNU GPL Version 3 or later
#
# Note: the bits in Global Inits, which is part of GTK-server bash init code
#       is (C) Peter van Eerten. Everything else is (C) James Budiono
#
#131106 L18L internationalization
#20171230 jamesbond Finally do the group management

# std localisation stanza
export TEXTDOMAIN=fatdog
. gettext.sh
# performance tweak - use "C" if there is no localisation
! [ -e $TEXTDOMAINDIR/${LANG%.*}/LC_MESSAGES/$TEXTDOMAIN.mo ] &&
! [ -e $TEXTDOMAINDIR/${LANG%_*}/LC_MESSAGES/$TEXTDOMAIN.mo ] && LANG=C


### configuration
APPTITLE="$(gettext 'Fatdog64 User Manager')"
SYSTEM_MANAGED_USERS="root spot" # system-managed users cannot be deleted.
MANAGED_USERS_GROUP="users"     # we only manage users in this group, if empty, manage all users
MIN_MEMBER_UID=1000             # mininum member of uid that we want to allow to add as member
WARN_LOW_GID=1000               # group lower than this will get a warning
WARN_LOW_UID=1000               # userid lower than this will get a warning
PASSWD_ALGO=md5					# busybox understands des,md5,sha256,sha512
DEFAULT_PASSWORD=woofwoof		# default password for new user
AUTOLOGIN_CONFIG=/etc/autologin	# control file for autologin
[ -r /etc/fatdog-user-manager.conf ] && . /etc/fatdog-user-manager.conf # override if need be

[ $(id -u) -ne 0 ] && exec gtksu "$APPTITLE" "$0"

### runtime variables
GDK_TYPE_PIXBUF=
MAIN_WINDOW=

# userstore tree model
UT_USERID=0

# groupstore tree model
GT_GROUPID=0

# groupmemberstore tree model
GMT_USERID=0

#---------------------------------------------------------- Global Inits
### global variables for proper GTK-server
GTK= NULL="NULL"
PIPE=/tmp/gtk.bash.$$
trap 'stop-gtk-server -fifo $PIPE; exit' HUP TERM INT # stop GTK-server in case of an error

### start GTK-server
gtk-server -fifo=$PIPE &
while [ ! -p $PIPE ]; do sleep 1; continue; done

### GTK-server helper functions
# Assignment function
define() { $2 $3 $4 $5 $6 $7 $8 $9; eval $1=\'"$GTK"\'; }

# Communicate with GTK-server
gtk()
{
/bin/echo "$@" > $PIPE
read GTK < $PIPE
}

#---------------------------------------------------------- GUI realization

# add GTK+ API not defined in gtk-server.cfg
add_missing_gtk_api() {
	gtk gtk_server_define gdk_pixbuf_get_type NONE INT 0
	gtk gtk_server_define gtk_label_set_markup NONE NONE 2 WIDGET STRING
	
	# add GTK+ API not defined in gtk-server.cfg
	gtk gtk_server_define gtk_builder_new NONE WIDGET 0
	gtk gtk_server_define gtk_builder_add_from_file NONE INT 3 WIDGET STRING NULL
	gtk gtk_server_define gtk_builder_add_from_string NONE INT 4 WIDGET STRING INT NULL
	gtk gtk_server_define gtk_builder_get_object NONE WIDGET 2 WIDGET STRING
	gtk gtk_server_define gtk_builder_connect_signals NONE NONE 2 WIDGET NULL	
	
	gtk gtk_server_define gtk_tree_view_get_cursor NONE NONE 3 WIDGET PTR_WIDGET NULL
	
	# hack for getting unlimited string length and leak-free operation with gtk_tree_get_model
	# see below
	gtk gtk_server_define strcat NONE STRING 2 POINTER STRING
	gtk gtk_server_define memcpy NONE NONE 3 PTR_LONG POINTER INT			
}

### helper - leak-free, unlimited string length from gtk_tree_model_get with unpatched gtk-server
# $1-tree $2-iter $3-index $4-result name
# static variable to speed up stuff
STATIC_BUF=
STATIC_ADDRESS=
tree_model_get_string() {
	[ -z "$STATIC_BUF" ] && define STATIC_BUF gtk malloc 32 # gtk-server MAX_DIG is 32 bytes
	
	gtk gtk_server_define gtk_tree_model_get NONE NONE 5 WIDGET WIDGET INT POINTER INT # ensure correct definition
	gtk gtk_tree_model_get $1 $2 $3 $STATIC_BUF -1
	
	gtk memcpy NULL $STATIC_BUF 32	# print address stored in $BUF --> *buf
	STATIC_ADDRESS=$GTK
	if [ $STATIC_ADDRESS -ne 0 ]; then
		gtk strcat $STATIC_ADDRESS \"\" # get string point by address --> **buf	
		eval $4=\'"$GTK"\'				# this will be our return value	
		gtk free $STATIC_ADDRESS		# this was dynamically alloc-ed by gtk_tree_model_get, now free it
	else
		eval $4=\"\"
	fi
}

# $* text to show
infobox() {
	local TITLE=${TITLE:-$APPTITLE}
	Xdialog --title "$TITLE" --infobox "$*" 0 0 10000
}

# $* text to show
yesno() {
	local TITLE=${TITLE:-$APPTITLE}
	Xdialog --title "$TITLE" --yesno "$*" 0 0 
}

# $* text to show
inputbox() {
	local TITLE=${TITLE:-$APPTITLE}
	Xdialog --title "$TITLE" --stdout --inputbox "$*" 0 0
}

# $* text to show
password_inputbox() {
	local TITLE=${TITLE:-$APPTITLE}
	Xdialog --title "$TITLE" --password --stdout --inputbox "$*" 0 0
}

################### misc hlpers ###################

#
get_all_groups() {
	awk -F: '{print $1}' /etc/group
}

#
get_all_users() {
	awk -F: '{print $1}' /etc/passwd
}

# $1-group
get_members_of_a_group() {
	awk -F: -v group="$1" '$1 == group {gsub(/,/,"\n",$4); print $4}' /etc/group
}

#$1-userid
userid_exists() {
	test "$(awk -F: -v user="$1" '$1 == user {print $1}' /etc/passwd)"
}

# $1-userid
get_user_homedir() {
	awk -v user="$1" -F: '$1 == user { print $6 }' /etc/passwd	
}

# $1-userid
get_user_uid() {
	awk -v user="$1" -F: '$1 == user { print $3 }' /etc/passwd	
}

# $1-userd
get_printable_userid_details() {
	< /etc/passwd awk -v user=$1 -F: '
BEGIN { ORS="" }
$1 == user {
	sub(/,.*/,"",$5)
	print $5 "\\n\\n"
	print "uid: " $3 "\\n"
	print "gid: " $4 "\\n"
	print "shell: " $7 "\\n"
	print "home: " $6 "\\n"		
}'
}

# get userids whose uid meet $1-filter requirements
get_userid_filter_by_uid() {
	awk -F: '$3 '"$1"' {print $1}' /etc/passwd
}

# $1-groupid
groupid_exists() {
	test "$(awk -F: -v group="$1" '$1 == group {print $1}' /etc/group)"
}

# $1-groupid
get_group_gid() {
	awk -v group="$1" -F: '$1 == group { print $3 }' /etc/group
}

### helper - returns true if the user is managed by system
# $1-user
is_system_managed() {
	for p in $SYSTEM_MANAGED_USERS; do
		case $p in $1) 
			return 0
		esac
	done
	return 1
}

# $1-newid
sanitise_newid() {
	echo "$1" | sed 's/[^A-Za-z0-9._-|]*//g'	
}

# $1-groupid
warn_low_gid() {
	local group=$1
	if [ $(get_group_gid $group) -ge $WARN_LOW_GID ]; then
		return 0 # proceed
	else
		yesno "$(eval_gettext '$group is a system group. Continue?')"
	fi
}

# $1-userid
warn_low_uid() {
	local user=$1
	if [ $(get_user_uid $user) -ge $WARN_LOW_UID ]; then
		return 0 # proceed
	else
		yesno "$(eval_gettext '$user is a system user. Continue?')"
	fi
}


################### user management ###################

### helper - refresh the content of userview by loading it from /etc/group
refresh_userview() {
	local ITER users
	define ITER gtk gtk_server_opaque
	
	gtk gtk_list_store_clear $USERSTORE
	
	if [ "$MANAGED_USERS_GROUP" ]; then
		users="$(get_members_of_a_group $MANAGED_USERS_GROUP)"
		gtk gtk_list_store_append $USERSTORE $ITER NULL # add root
		gtk gtk_list_store_set $USERSTORE $ITER $UT_USERID root -1 NULL -1		
	else
		users="$(get_all_users)"
	fi
	
	for p in $users; do
		gtk gtk_list_store_append $USERSTORE $ITER NULL
		gtk gtk_list_store_set $USERSTORE $ITER $UT_USERID $p -1 NULL -1
	done
	
	gtk free $ITER
}

### helper - get the currently selected userid
# returns SELECTED_USERID
get_selected_user() {
	local ITER SELECTED_PATH
	define ITER gtk gtk_server_opaque
	
	define SELECTED_PATH gtk gtk_tree_view_get_cursor $USERVIEW NULL
	if [ $SELECTED_PATH -ne 0 ]; then
		gtk gtk_tree_model_get_iter $USERSTORE $ITER $SELECTED_PATH	
		gtk gtk_tree_path_free $SELECTED_PATH

		# $1-tree $2-iter $3-index $4-result name
		tree_model_get_string $USERSTORE $ITER $UT_USERID SELECTED_USERID
	fi
	
	gtk free $ITER
}

### signal handler - update and display user details info
#$1-userid
update_user_details() {
	local THIS_USER
	THIS_USER="$1"
	local msg="$(get_printable_userid_details $1)"
	if ps -o user -C freemem.sh | grep -qm 1 $1; then
		if [ $USER = $1 ]; then
			msg="$msg\n$(gettext 'Owner of this desktop.')\n"
		else
			msg="$msg\n$(eval_gettext '${THIS_USER} has a desktop running in the background.')\n"
		fi
	fi
	gtk gtk_label_set_markup $USER_DETAILS_FRAME_LABEL \""<b>$1</b>"\"	
	gtk gtk_label_set_markup $USER_DETAILS_LABEL \""$msg"\"
	gtk gtk_widget_show $USER_DETAILS_FRAME	
}

### signal handler - create new user
add_new_user() {
	local newid TITLE
	if newid=$(inputbox "$(gettext 'Please enter the userid. It must not be the same as existing ones.')"); then
		newid=$(sanitise_newid "$newid") # remove all funny characters
		if userid_exists $newid; then
			TITLE="$(gettext 'Error!')" \
			infobox "$(eval_gettext '$newid already exist. Please choose another userid.')"
		else
			mkuser.sh $newid
			echo -e "$DEFAULT_PASSWORD\n$DEFAULT_PASSWORD\n" | passwd -a md5 $newid
			refresh_userview
			refresh_groupview
			TITLE="$(gettext 'Success!')" \
			infobox "$(eval_gettext 'User $newid is created. Password is set to $DEFAULT_PASSWORD.')"
		fi
	fi
}

### signal handler - delete user
#$1-userid
del_user() {
	local THIS_USER TITLE
	THIS_USER="$1"
	if is_system_managed $1; then
		TITLE="$(gettext 'Error!')" \
		infobox "$(eval_gettext "${THIS_USER} is a system-managed user, it cannot be deleted.")"
		return	
	fi

	if [ $USER = $1 ]; then
		TITLE="$(gettext 'Error!')" \
		infobox "$(gettext 'You cannot delete yourself.')"
		return	
	fi
	
	local homedir
	homedir=$(get_user_homedir $1)
	if yesno "$(eval_gettext "Do you really want to remove user $THIS_USER? 
All files in ${THIS_USER}'s home directory ($homedir) will be deleted.")"; then
		rmuser.sh $THIS_USER
		refresh_userview
		refresh_groupview
		gtk gtk_widget_hide $USER_DETAILS_FRAME
	fi
    #' (this line is just to satisfy geany highlighting)
}

### signal handler - set password for user
#$1-userid
set_password() {
	local newpwd
	local THIS_USER
	THIS_USER="$1"
	if newpwd=$(password_inputbox "$(gettext 'Enter new password (blank means no password required)')"); then
		newpwd=$(echo $newpwd) # cheap way to remove leading/trailing spaces
		if [ "$newpwd" ]; then
			echo -e "$newpwd\n$newpwd\n" | passwd -a $PASSWD_ALGO $1
			infobox "$(eval_gettext "${THIS_USER}' s password is updated successfully.")"
		else
			infobox "$(eval_gettext "${THIS_USER}'s password is removed - everyone can login as ${THIS_USER} without password.")"
			passwd -d $1
		fi
	fi
}

### signal handler - launch desktop as a specified user
# $1-user
launch_desktop_as_user() {
	local FGCONSOLE="$(fgconsole)"
	local THIS_USER TITLE
	THIS_USER="$1"
	local disp pid tty
	[ $USER = $1 ] && return
	
	# check if user is already running a desktop
	if ! pid=$(ps -o pid=,user= -C freemem.sh | grep $1); then 
		for disp in $(seq 1 10); do
			[ ! -e /tmp/.X${disp}-lock ] && break
		done
		TITLE="$(gettext 'Attention!')" \
		infobox "$(eval_gettext "About to launch a secondary desktop, running as ${THIS_USER}.")

$(gettext 'You can switch between desktops using Ctrl-LeftAlt-Fx, where x=4,5,6 etc.') 
$(eval_gettext 'Use Ctrl-LeftAlt-F${FGCONSOLE} to switch back to this desktop.')

$(gettext 'To terminate the secondary desktop, choose "Exit X server" or "Restart X server" from the menu.')"
		su - $1 -c "/bin/bash -l -c \"xinit -- :${disp}\"" &
	else
		TITLE="$(gettext 'Attention!')" \
		infobox "$(eval_gettext "Switching to ${THIS_USER}'s desktop.") 
$(eval_gettext 'Use Ctrl-LeftAlt-F${FGCONSOLE} to switch back to this desktop.')"
		pid=$(echo ${pid% *})
		disp=$(cat /proc/$pid/environ | tr '\000' '\n' | sed '/^DISPLAY/ !d; s/^.*=//')
		tty=$(ps -o tty=,args= -C X,Xorg | sed "/$disp/ !d; s/ .*\$//")
		[ -z $tty ] && 	tty=$(ps -o tty=,args= -C X,Xorg | sed "/:/ d; s/ .*\$//")
		tty=${tty#tty}
		chvt $tty
	fi
    #' (this line is just to satisfy geany highlighting)
}

################### group management ###################

### helper - refresh the content of group by loading it from /etc/group
refresh_groupview() {
	local ITER
	define ITER gtk gtk_server_opaque

	gtk gtk_list_store_clear $GROUPMEMBERSTORE	# clear the memberlist too
	gtk gtk_list_store_clear $GROUPSTORE
	for p in $(get_all_groups); do
		gtk gtk_list_store_append $GROUPSTORE $ITER NULL
		gtk gtk_list_store_set $GROUPSTORE $ITER $GT_GROUPID $p -1 NULL -1
	done

	gtk free $ITER
}

### helper - refresh the content of members by loading it from /etc/group
# $1-group
refresh_groupmemberview() {
	[ "$1" ] || return
	local ITER
	define ITER gtk gtk_server_opaque

	gtk gtk_list_store_clear $GROUPMEMBERSTORE
	for p in $(get_members_of_a_group $1); do
		gtk gtk_list_store_append $GROUPMEMBERSTORE $ITER NULL
		gtk gtk_list_store_set $GROUPMEMBERSTORE $ITER $GMT_USERID $p -1 NULL -1
	done

	gtk free $ITER
}

### helper - get the currently selected groupid
# returns SELECTED_GROUPID
get_selected_group() {
	local ITER SELECTED_PATH
	define ITER gtk gtk_server_opaque

	SELECTED_GROUPID=
	define SELECTED_PATH gtk gtk_tree_view_get_cursor $GROUPVIEW NULL
	if [ $SELECTED_PATH -ne 0 ]; then
		gtk gtk_tree_model_get_iter $GROUPSTORE $ITER $SELECTED_PATH	
		gtk gtk_tree_path_free $SELECTED_PATH

		# $1-tree $2-iter $3-index $4-result name
		tree_model_get_string $GROUPSTORE $ITER $GT_GROUPID SELECTED_GROUPID
	fi
	
	gtk free $ITER
}

### helper - get the currently selected member
# returns SELECTED_MEMBERID
get_selected_member() {
	local ITER SELECTED_PATH
	define ITER gtk gtk_server_opaque
	
	SELECTED_MEMBERID=
	define SELECTED_PATH gtk gtk_tree_view_get_cursor $GROUPMEMBERVIEW NULL
	if [ $SELECTED_PATH -ne 0 ]; then
		gtk gtk_tree_model_get_iter $GROUPMEMBERSTORE $ITER $SELECTED_PATH	
		gtk gtk_tree_path_free $SELECTED_PATH

		# $1-tree $2-iter $3-index $4-result name
		tree_model_get_string $GROUPMEMBERSTORE $ITER $GMT_USERID SELECTED_MEMBERID
	fi
	
	gtk free $ITER
}

### signal handler - add group member
# $1-groupid
add_member() {
	local pp p group=$1 user
	pp=""
	for p in $(get_userid_filter_by_uid ">= $MIN_MEMBER_UID"); do
		pp="$pp $p $p"
	done
	[ "$pp" ] || return
	if user=$(Xdialog --stdout --no-tags --ok-label "$(gettext 'Add')" --title "$APPTITLE" \
		--menubox "$(eval_gettext 'Select user to add to the $group group.')\n\
		$(eval_gettext 'Note: Only users with uid >= $MIN_MEMBER_UID is shown.')" 0 0 5 $pp);
	then
		busybox addgroup $user $group
		refresh_groupmemberview $group
	fi
}

### signal handler - remove group member
# $1-groupid $2-member to delete
del_member() {
	local group=$1 member=$2
	if warn_low_gid $group && warn_low_uid $member; then
		if yesno "$(eval_gettext "Do you really want to remove $member from group $group?")"; then
			busybox delgroup $member $group
			refresh_groupmemberview $group
		fi	
	fi
}

### signal handler - add new group
add_group() {
	local newid TITLE
	if newid=$(inputbox "$(gettext 'Please enter the groupid. It must not be the same as existing ones.')"); then
		newid=$(sanitise_newid "$newid") # remove all funny characters
		if groupid_exists $newid; then
			TITLE="$(gettext 'Error!')" \
			infobox "$(eval_gettext '$newid already exist. Please choose another groupid.')"
		else
			busybox addgroup $newid
			refresh_groupview
			TITLE="$(gettext 'Success!')" \
			infobox "$(eval_gettext 'Group $newid is created.')"
		fi
	fi
}

### signal handler - delete group
# $1-group to delete
del_group() {
	local group=$1
	# caution - warn if gid less than 1000
	if warn_low_gid $group; then
		if yesno "$(eval_gettext "Do you really want to remove group $group?")"; then
			busybox delgroup $group
			refresh_groupview
		fi
	fi
}

################### main ###################

### localisation
[ -z $TEXTDOMAINDIR ] && TEXTDOMAINDIR=/usr/share/locale
[ -z $TEXTDOMAIN ] && TEXTDOMAIN=fatdog64
gtk gtk_server_define setlocale NONE STRING 2 INT STRING
gtk gtk_server_define bindtextdomain NONE STRING 2 STRING STRING
gtk gtk_server_define textdomain NONE STRING 1 STRING
gtk setlocale 6 \"\" # 6 corresponds to LC_ALL
gtk bindtextdomain $TEXTDOMAIN $TEXTDOMAINDIR
gtk textdomain $TEXTDOMAIN

### init gui
add_missing_gtk_api
gtk gtk_init
define GDK_TYPE_PIXBUF gtk gdk_pixbuf_get_type

define BUILDER gtk gtk_builder_new
define RESULT gtk gtk_builder_add_from_file $BUILDER "${0}.xml"
gtk gtk_builder_connect_signals $BUILDER

define MAIN_WINDOW gtk gtk_builder_get_object $BUILDER main_window
define CLOSE_BUTTON gtk gtk_builder_get_object $BUILDER close-button

define USER_DETAILS_FRAME gtk gtk_builder_get_object $BUILDER user-details-frame
define USER_DETAILS_LABEL gtk gtk_builder_get_object $BUILDER user-details-label
define USER_DETAILS_FRAME_LABEL gtk gtk_builder_get_object $BUILDER user-details-frame-label

define ADD_USER_BUTTON gtk gtk_builder_get_object $BUILDER add-user-button
define DELETE_USER_BUTTON gtk gtk_builder_get_object $BUILDER delete-user-button
define SET_PASSWORD_BUTTON gtk gtk_builder_get_object $BUILDER set-password-button
define AUTOLOGIN_AS_USER_BUTTON gtk gtk_builder_get_object $BUILDER autologin-as-user-button
define LAUNCH_DESKTOP_AS_USER_BUTTON gtk gtk_builder_get_object $BUILDER launch-desktop-as-user-button

define USERVIEW gtk gtk_builder_get_object $BUILDER userview
define USERSTORE gtk gtk_builder_get_object $BUILDER userstore

define GROUPVIEW gtk gtk_builder_get_object $BUILDER groupview
define GROUPSTORE gtk gtk_builder_get_object $BUILDER groupstore
define GROUPMEMBERVIEW gtk gtk_builder_get_object $BUILDER groupmemberview
define GROUPMEMBERSTORE gtk gtk_builder_get_object $BUILDER groupmemberstore

define NEW_GROUP_BUTTON gtk gtk_builder_get_object $BUILDER new-group-button
define DELETE_GROUP_BUTTON gtk gtk_builder_get_object $BUILDER delete-group-button
define ADD_MEMBER_BUTTON gtk gtk_builder_get_object $BUILDER add-member-button
define REMOVE_MEMBER_BUTTON gtk gtk_builder_get_object $BUILDER remove-member-button


# connect signals
gtk gtk_server_connect $MAIN_WINDOW delete-event quit
gtk gtk_server_connect $CLOSE_BUTTON clicked quit
gtk gtk_server_connect $USERVIEW cursor-changed userview-cursor-changed
gtk gtk_server_connect $ADD_USER_BUTTON clicked add-user
gtk gtk_server_connect $DELETE_USER_BUTTON clicked del-user
gtk gtk_server_connect $SET_PASSWORD_BUTTON clicked set-password
gtk gtk_server_connect $AUTOLOGIN_AS_USER_BUTTON clicked autologin-user
gtk gtk_server_connect $LAUNCH_DESKTOP_AS_USER_BUTTON clicked launch-desktop

gtk gtk_server_connect $GROUPVIEW cursor-changed groupview-cursor-changed
gtk gtk_server_connect $NEW_GROUP_BUTTON clicked new-group
gtk gtk_server_connect $DELETE_GROUP_BUTTON clicked delete-group
gtk gtk_server_connect $ADD_MEMBER_BUTTON clicked add-member
gtk gtk_server_connect $REMOVE_MEMBER_BUTTON clicked remove-member

# preparation stuff
refresh_userview
refresh_groupview

### gtk main loop
gtk gtk_widget_show_all $MAIN_WINDOW
gtk gtk_widget_hide $USER_DETAILS_FRAME
! grep -q autologin /etc/inittab && gtk gtk_widget_hide $AUTOLOGIN_AS_USER_BUTTON
while true; do 
	define EVENT gtk gtk_server_callback wait
	case $EVENT in
		quit)
			break ;;

		### user ###
		userview-cursor-changed) 
			get_selected_user 
			update_user_details $SELECTED_USERID ;;
			
		add-user) 
			add_new_user ;;
			
		del-user)
			get_selected_user
			del_user $SELECTED_USERID ;;
			
		set-password)
			get_selected_user
			set_password $SELECTED_USERID ;;
			
		autologin-user)
			get_selected_user
			echo $SELECTED_USERID > $AUTOLOGIN_CONFIG 
			chmod 0600 $AUTOLOGIN_CONFIG # root only
			infobox "$(eval_gettext 'At next reboot the system will auto-login as $SELECTED_USERID')"
			;;
			
		launch-desktop)
			get_selected_user
			launch_desktop_as_user $SELECTED_USERID
			;;

		### group ###
		groupview-cursor-changed)
			get_selected_group
			refresh_groupmemberview $SELECTED_GROUPID
			;;
			
		new-group)
			add_group
			;;
			
		delete-group)
			get_selected_group
			if [ "$SELECTED_GROUPID" ]; then
				del_group $SELECTED_GROUPID
			else
				infobox "$(gettext 'Choose a group first.')"
			fi
			;;
			
		add-member)
			get_selected_group
			if [ "$SELECTED_GROUPID" ]; then
				add_member $SELECTED_GROUPID
			else
				infobox "$(gettext 'Choose a group from the left first.')"
			fi
			;;
			
		remove-member)
			get_selected_group
			if [ "$SELECTED_GROUPID" ]; then
				get_selected_member
				if [ "$SELECTED_MEMBERID" ]; then
					del_member $SELECTED_GROUPID $SELECTED_MEMBERID
				else
					infobox "$(gettext 'Choose a member first.')"
				fi
			else
				infobox "$(gettext 'Choose a group from the left first.')"
			fi		
			;;
			
	esac
done
gtk gtk_server_exit 
