#!/bin/bash
#
# /usr/local/sbin/localmkpostfixvirtual
# Copyright 2001-2002 Jonas Smedegaard <dr@jones.dk>
#
# $Id: localmkpostfixvirtual,v 1.17 2004-08-19 14:40:32 jonas Exp $
#
# Generate virtual file for postfix
#
# Hints are stored in the "Other" field (using chfn).
#
# Each user should have space-separated hints like this:
# "mailname1@ mailname2@mailgroup1 mailname3@mailgroup2 mailname4@maildomain7".
#
# The user of each mailgroup should have hints like "@domain1 @domain2"
# for each hosted maildomain.
#
# Generate virtual file like this:
#
#  # ( cd /etc/postfix && localmkpostfixvirtual > virtual.new && diff virtual virtual.new )
#
# ..and if the changes are correct, activate the new virtual file:
#
#  # ( cd /etc/postfix && mv virtual.new virtual && postmap virtual )
#
# Optional: Several mailgroups can be tied together (when amount of hints
# exceeds the limit of the "Other" field: List them all in
# "Office" or "roomnumber" field of primary mailgroup (include the
# primary mailgroup itself!).
#
# Optional: root can have hints like "postmaster@ hostmaster@ support@"
# for default accounts tied to the sysadmin (default: "postmaster@").
#
# Suggestion: Add mailgroup users like this:
# adduser --system --no-create-home --group --disabled-password <uid>
#
# TODO: reuse getent requests (drastically improves speed)
# TODO: Write command "members" as internal code
#

function get_fullname_field()	{ getent passwd $1 | awk -F: '{print $5}' | awk -F, '{print $1}'; }
function get_roomnumber_field()	{ getent passwd $1 | awk -F: '{print $5}' | awk -F, '{print $2}'; }
function get_other_field()	{ getent passwd $1 | awk -F: '{print $5}' | awk -F, '{print $5}'; }
function get_groups()		{ groups $1 | sed -e 's/^.*: //' -e "s/\( \+\|^\)$1\( \+\|$\)/\1/"; }
function get_domain()		{ echo $1 | egrep "^@[\.[:alnum:]-]+$" | sed -e 's/@//'; }
function get_account()		{ echo $1 | egrep "^([\.[:alnum:]_-]+|\+)@($gid|$maildomain)?$" | sed -e 's/@.*//'; }

function print_accounts() {
	uid=$1
	maildomain=$2
	pre_text=$3
	post_fallback_text=$4

	test -n "$pre_text" && echo "$pre_text"
	uid_seen=""
	joker_seen=""
	for mailaccountchunk in `get_other_field $uid`; do
		for mailaccount in `get_account $mailaccountchunk`; do
			case $mailaccount in
			    '+')
				if [ -z "$joker_seen" ]; then
					echo "@$maildomain $uid"
					joker_seen="$uid"
				else
					echo "#WARNING: Catch-all for $maildomain already set to $joker_seen: `get_fullname_field $uid`"
				fi
				;;
			    *)
				echo "$mailaccount@$maildomain $uid"
				;;
			esac
			uid_seen=1
		done
	done
	test -n "$post_fallback_text" -a -z "$uid_seen" && echo "$post_fallback_text"
	echo
}

loop=""
if [ $# -lt 1 ]; then
	mailgroups="`members maildomains`"
else
	mailgroups="$@"
fi
for gid in $mailgroups; do
	for maildomainchunk in `get_other_field $gid`; do
		for maildomain in `get_domain $maildomainchunk`; do
			if [ $loop ]; then
				echo
				echo "##################################################################"
				echo
			fi
			loop=true
			print_accounts root "$maildomain" "$maildomain VIRTUAL" "postmaster@$maildomain root"
			mailgroupowners=""
			mailusers=""
			mailgroups=`get_roomnumber_field $gid`
			test -z "$mailgroups" && mailgroups=$gid
			for mailgroup in $mailgroups; do
				mailgroupowners="$mailgroup_owners `members -p $mailgroup`"
				mailusers="$mailusers `members -s $mailgroup`"
			done
			# Do mailgroup owners (and don't warn if there's no addresses attached)
			for uid in `for x in $mailgroupowners; do echo $x; done | uniq | sort`; do
				print_accounts $uid "$maildomain" "# `get_fullname_field $uid` (`get_groups $uid`)" ""
			done
			# Do secondary mailgroup members
			for uid in `for x in $mailusers; do echo $x; done | uniq | sort`; do
				print_accounts $uid "$maildomain" "# `get_fullname_field $uid` (`get_groups $uid`)" "#WARNING: No addresses for $uid"
			done
		done
	done
done