#!/bin/sh
#
# /usr/local/bin/localadduser
# Copyright 2003-2006 Jonas Smedegaard <dr@jones.dk>
#
# $Id: localadduser,v 1.5 2006-08-31 22:51:54 jonas Exp $
#
# Execute adduser noninteractively through sudo
#
# TODO: Check for bad arguments
# TODO: Implement --help option
# TODO: Support overriding options in /etc/local file
# TODO: Check gecos field length
# TODO: Check password strength of autogenerated password (and pick another if needed)
# TODO: Deal with non-ASCII chars (transliterate or silence chfn warnings)
# TODO: quiten output: only emit password line by default
# TODO: support reading from file or stdin
# TODO: Implement --update option: apply missing data to existing account
#

set -e

PRG=$(basename "$0")

TEMP="`getopt -s sh -o vqin -l verbose,quiet,interactive,noninteractive,dry-run -n "$PRG" -- "$@"`"
if [ $? != 0 ] ; then echo >&2 "ERROR: Internal getopt error." ; exit 1 ; fi
eval set -- "$TEMP"

verbose=1
interactive=0
while true ; do
	case "$1" in
		-v|--verbose) verbose=1; shift ;;
		-q|--quiet) verbose=0; shift ;;
		-i|--interactive) interactive=1; shift ;;
		-n|--noninteractive) interactive=0; shift ;;
		--dry-run) simulate=true; shift ;;
		--) shift ; break ;;
		*) echo >&2 "ERROR: Internal error resolving options." ; exit 1 ;;
	esac
done

# echo something, but only if in verbose mode
vecho() {
	test -n "$verbose" && echo "$@" >&2
}

exit1() {
	response="${1:+Error: }${1:-Internal error!}"
	echo "$response"
	exit 1
}

u=$1
shift

for chunk in $@; do
	case $chunk in
	    @*)
		groupchunks="${groupchunks:+$groupchunks }$chunk"
		;;
	    %*)
		officechunks="${officechunks:+$officechunks }$chunk"
		;;
	    *@*)
		other="${other:+$other }$chunk"
		;;
	    +*)
		phone_area="$chunk"
		;;
	    0*|1*|2*|3*|4*|5*|6*|7*|8*|9*)
		if [ -z "$phone_area" ]; then
			exit1 "Phone number provided without leading area code!"
		fi
		if [ -n "$home_phone" ]; then
			exit1 "More than 2 phone numbers provided!"
		elif [ -n "$office_phone" ]; then
			office_phone="$phone_area $chunk"
		else
			home_phone="$phone_area $chunk"
		fi
		phone_area=""
		;;
	    *)
		fullname="${fullname:+$fullname }$chunk"
		;;
	esac
done

if getent passwd "$u" | grep -q .; then
	exit1 "User \"$u\" already exists!"
fi
if getent group "$u" | grep -q .; then
	exit1 "Group \"$u\" already exists!"
fi

if [ -n "$phone_area" ]; then
	exit1 "Area code provided without trailing phonenumber!"
fi

for groupchunk in $groupchunks; do
	group="$(echo "$groupchunk" | perl -pe 's/^@//;')"
	if echo "$group" | perl -ne '/^[a-z][a-z0-9_-]*$/ and exit 1;'; then
		exit1 "Group \"$group\" contains illegal characters!"
	fi
	if ! members="$(getent group "$group")"; then
		exit1 "Group \"$group\" does not exist!"
	fi
	if echo "$members" | perl -pe 's/.*://; s/,/\n/g' | grep -Fxq "$u"; then
		exit1 "Group \"$group\" already contains user \"$u\"!"
	fi
	groups="${groups:+$groups }$group"
done

for officechunk in $officechunks; do
	office="${office:+$office }$(echo "$officechunk" | perl -pe 's/^%//;')"
done

if [ ! "$interactive" -gt 0 ]; then
	quiet="--quiet"
fi

# adduser is too pessimistic on --gecos size
eval $simulate sudo "/usr/sbin/adduser $quiet --disabled-login --gecos \"\" \"$u\""
eval $simulate sudo "/usr/sbin/usermod -c \"$fullname,$office,$office_phone,$home_phone,$other\" \"$u\""

for group in $groups; do
	eval $simulate sudo "/usr/sbin/adduser $quiet \"$u\" \"$group\""
done

eval $simulate localresetpasswd "$u"

#vecho "Account \"$u\" created succesfully! Password is $pass"