#!/bin/bash
# m7 - mailman helper

set -e

source "/home/zwelch/src/mcf/mcsh-release/install/share/mcsh/mcsh.sh"

lib_load 'sys/server'


######
# Configuration

m7_config_init() {
	script_setting_vars -ro mm_dir mm_bindir
	script_setting_vars mailman_host mailman_server mailman_user
}

m7_config_check() {
	mm_bindir=${mm_bindir:-$mm_dir/bin}
	mailman_server=${mailman_server:-$(server_name "$mailman_host")}
	debug "mailman host: $mailman_host ($mailman_server)"
	if [ "$host" != "$mailman_server" ]; then
                warn "run this command on a mailman server (not '$host')"
        fi
}


######
# Native dependencies

m7_server_packages=( mailman )


######
# Low-level helpers

run_mm_bin() {
	local cmd=$1
	shift
	run_sudo_as_user $mailman_user $mm_bindir/$cmd "$@"
}

mm_change_pw() {
	min_args 1 "$@"
	local list=$1
	shift
	run_mm_bin change_pw "$@" -l "$list" |cut -d' ' -f4
}

mm_config() {
	local opt=$1
	local list=$2
	shift 2
	local file="$(list_config $list 'list.conf')"
	run_mm_bin config_list $opt $file "$@" $list
}

mm_withlist() {
	run_pushd "$mm_bindir"
	run_mm_bin withlist "$@"
	run_popd
}


######
# Alias file management

alias_exists() {
	has_args 1 "$@"
	grep "^$1: " $PREFIX/etc/aliases
}
alias_add() {
	has_args 2 "$@"
	local name tgt
	name=$1
	tgt=$2
	if alias_exists $name; then
		warn "$name: alias exists"
		return
	fi

	local tmp
	tmp=$(cmd_tempfile)
	run cp /etc/aliases $tmp
	app_echo "$name: adding alias..."
	echo "$name: $tgt" >>$tmp
	run_sudo mv $tmp $PREFIX/etc/aliases
}
alias_remove() {
	has_args 1 "$@"
	local list tmp
	list=$1
	tmp=$(cmd_tempfile)
	run cp /etc/aliases $tmp
	grep -v"'^$list:" $PREFIX/etc/aliases >$tmp
}
aliases() {
	grep '^[^:]*:' $PREFIX/etc/aliases |cut -f1 -d':'
}

admin_alias_exists() {
	has_args 1 "$@"
	alias_exists "${1}-owner"
}

aliases_install() {
	local src=$1
	run install_as_root "$src" $PREFIX/etc/aliases 0644
	run_sudo newaliases
}

aliases_add() {
	has_args 1 "$@"
	local aliases=$1
	[ -f "$aliases" ] || error "$aliases: alias file missing"

	local tmp
	tmp=$(cmd_tempfile)
	cat /etc/aliases "$aliases" >>"$tmp"

	aliases_install $tmp
}

aliases_remove() {
	has_args 1 "$@"
	local aliases=$1
	[ -f "$aliases" ] || error "$aliases: alias file missing"

	local tmp
	tmp=$(cmd_tempfile)
	grep -f "$aliases" -v /etc/aliases >$tmp

	aliases_install $tmp
}


######
# Mailman List Aliases

mailman_alias_suffixes=(
		'' admin bounces confirm join leave owner
		request subscribe unsubscribe
	)

mailman_alias_build() {
	local s="                       "
	local p="${s:0:$3}"
	echo "$1:$p \"|$2\""
}

mailman_alias_list() {
	has_args 1 "$@"
	local l=$1
	local a
	for a in "${mailman_alias_suffixes[@]}"; do
		local pipe="$mm_dir/mail/mailman ${a:-post} $l"
		if [ -z "$a" ]; then
			mailman_alias_build "$l" "$pipe" 13
		else
			local n=$((12 - ${#a}))
			mailman_alias_build "$l-$a" "$pipe" $n
		fi
	done
}
mailman_alias_generate() {
	has_args 1 "$@"
	local name=$1
	local aliases
	aliases=$(list_config "$name" 'aliases')
	[ -f "$aliases" ] || error "$aliases: file exists"
	mailman_alias_list "$name" >"$aliases"
}

######
# List management

for_each_list() {
	min_args 1 "$@"
	local cmd=$1
	shift

	seed_sudo

	local -a lists
	if [ -z "$*" ]; then
		lists=( $(list_lists) )
	else
		lists=( "$@" )
	fi

	local list
	for list in "${lists[@]}"; do
		$cmd $list
	done
}

list_config() {
	has_args 2 "$@"
	echo "$script_confdir/lists.d/$1/$2"
}

list_secret_save() {
	has_args 2 "$@"
	local list passwd src dst
	list=$1
	passwd=$2

	src=$(cmd_tempfile)
	echo $passwd >$src

	dst=$(list_config $list 'secret.txt')
	run_sudo_install 0770 root list -d "$(dirname $dst)"
	run_sudo_install 0660 root list $src $dst
}

list_passwd_show() {
	has_args 1 "$@"
	local list=$1
	local secret
	secret=$(list_config $list 'secret.txt')
	if sudo test -f "$secret"; then
		echo -n "$list: "
		sudo cat $secret
	else
		error "$list: no such list"
	fi
}

list_change_pw() {
	has_args 1 "$@"
	local list passwd
	list=$1
	app_echo "$list: resetting..."
	passwd=$(mm_change_pw $list)
	list_secret_save "$list" "$passwd"
}


passwd_gen() {
	apg -c $RANDOM -n 1
}


list_new() {
	has_args 3 "$@"
	local domain=$1
	local name=$2
	local passwd=$3

	run_mm_bin newlist -a \
		--urlhost="$mailman_host.$domain" \
		--emailhost="$domain" \
		"$name" "list-admin@$domain" \
		"$passwd"
}

list_lists() {
	run_mm_bin list_lists -b "$@"
}

list_exists() {
	has_args 1 "$@"
	list_lists | egrep "^$1$"
}

##
# CLI commands

m7_list() { cmd_dispatch "$@"; }
m7_list_usage() {
	cat <<EOF
<cmd> [...]
List Query Commands:
	all				Prints list of all mailing lists
	public				Prints list of all public lists
	private				Prints list of all private lists
	exists <list>			Returns success if list exists
EOF
}

install_as_root() {
	min_args 2 "$@"
	local src dst mode user
	src=$1
	dst=$2
	mode=${3:-0600}
	user=${4:-root:root}
	pipe_to_sudo <<EOF
mv $src $dst
chmod $mode $dst
chown $user $dst
EOF
}


m7_new() {
	min_max_args 1 2 "$@"
	local name=$1
	! list_exists $name || error "$name: exists"

	local ldomain=${2:-$domain}

	local passwd
	passwd=$(passwd_gen)
	list_secret_save "$name" "$passwd"

	local aliases
	aliases=$(cmd_tempfile)
	list_new "$ldomain" "$name" "$passwd" |tail -n11 |head -n10 >"$aliases"

	aliases_add "$aliases"
}

m7_delete() {
	has_args 1 "$@"
	local list=$1

	local aliases
	aliases=$(cmd_tempfile)
	run_mm_bin rmlist "$list" |tail -n12 |head -n10 >$aliases

	aliases_remove "$aliases"
}

m7_rename() { cmd_dispatch "$@"; }

m7_rename_usage() {
	cat <<USAGE
...
List Rename Commands:
	all <old> <new>			Renames all mailing list settings
	config <old> <new>		Renames list configuration files
	files <old> <new>		Renames list data files
	archives <old> <new>		Renames list archives
	name <old> <new>		Renames list name
	aliases <old> <new>		Renames list aliases
USAGE
}

m7_rename_all() {
	m7_rename_config "$@"
	m7_rename_files "$@"
	m7_rename_archives "$@"
	m7_rename_name "$@"
	m7_rename_aliases "$@"
}

m7_rename_config() {
	has_args 2 "$@"
	local old=$1
	local new=$2

	local cdir="$script_confdir/lists.d"
	run mv "$cdir/$old" "$cdir/$new"
}

m7_rename_files() {
	has_args 2 "$@"
	local old=$1
	local new=$2

	local ldir="$mm_dir/lists"
	[ -d "$ldir/$old" ] || error "$old: list directory does not exist"
	[ ! -d "$ldir/$new" ] || error "$new: list directory already exists"

	run mv "$ldir/$old" "$ldir/$new"
}

m7_rename_archives() {
	has_args 2 "$@"
	local old=$1
	local new=$2

	local adir="$mm_dir/archives/private"
	local has_archive=true
	[ -f "$adir/$old.mbox/$old.mbox" ] || has_archive=false

	run mv "$adir/$old" "$adir/$new"
	run mv "$adir/$old.mbox" "$adir/$new.mbox"
	if $has_archive; then
		run mv "$adir/$new.mbox/$old.mbox" "$adir/$new.mbox/$new.mbox"
	fi

	run rm -f "$mm_dir/archives/public/$old"

	! $has_archive || run_mm_bin arch --wipe "$new"
}

m7_rename_name() {
	has_args 2 "$@"
	local old=$1
	local new=$2

	mm_withlist -l "$new" <<EOF
m.real_name = '$new'
m.Save()
EOF
}

m7_rename_aliases() {
	has_args 2 "$@"
	local old=$1
	local new=$2

	run cp /etc/aliases /etc/aliases.$(date +%y%m%d-%H%M%S)

	local tmp
	tmp=$(cmd_tempfile)
	mailman_alias_list "$old" >"$tmp"
	aliases_remove "$tmp"

	mailman_alias_list "$new" >"$tmp"
	aliases_add "$tmp"
}


m7_list_all() {
	has_args 0 "$@"
	list_lists
}
m7_list_public() {
	has_args 0 "$@"
	list_lists -a
}
m7_list_private() {
	has_args 0 "$@"
	local all pub pri a b
	all=( $(list_lists) )
	pub=( $(list_lists -a) )
	for a in "${all[@]}"; do
		local found=false
		for b in "${pub[@]}"; do
			if [ "$a" = "$b" ]; then
				found=true
			fi
		done
		$found || echo "$a"
	done
}
m7_list_secret() { list_passwd_show "$@"; }

m7_lists() { m7_list_all; }

######
# list passwords

m7_passwd() { cmd_dispatch "$@"; }
m7_passwd_usage() {
	cat <<EOF
<cmd> [<name>+]
Password Commands:
	show [<name+>]			Prints list admin password(s)
	reset [<name>+]			Resets list admin password(s)
EOF
}
m7_passwd_show() { for_each_list list_passwd_show "$@"; }
m7_passwd_reset() { for_each_list list_change_pw "$@"; }

######
# List Configuration Commands

m7_config() { cmd_dispatch "$@"; }

m7_config_usage() {
	cat <<USAGE
...
List Configuration Commands:
	get <list>+			Retreives list configuration(s)
	edit <list>			Edits the list configuration
	test <list>+			Checks list configuration(s)
	set <list>+			Sets list configuration(s)

	var ...				Configuration variable commands

Low-Level Configuration Commands:
	seturl <host> <list>+		Sets the URL/hostname for list
USAGE
}

_m7_config_get() {
	mm_config -o $1
	local conf
	conf=$(list_config $list 'list.conf')
	run_sudo_as_user $mailman_user chmod 0660 "$conf"
}
m7_config_get() { for_each_list _m7_config_get "$@"; }

_m7_config_test() { mm_config -ci $1; }
m7_config_test() { for_each_list _m7_config_test "$@"; }

_m7_config_set() { mm_config -i $1; }
m7_config_set() { for_each_list _m7_config_set "$@"; }

m7_config_edit() {
	has_args 1 "$@"
	local list=$1
	local conf
	conf=$(list_config $list 'list.conf')
	[ -f "$conf" ] || m7_config_get "$list"
	run_editor "$conf"
}

_m7_config_seturl() {
	local vopt
	! $verbose || vopt=-v
	mm_withlist -l -r fix_url "$1" "$vopt" -u "$urlhost"
}
m7_config_seturl() {
	min_args 1 "$@"
	local urlhost=$1
	shift
	for_each_list _m7_config_seturl "$@"
}


######
# List Configuration Variables

m7_config_var() { cmd_dispatch "$@"; }

m7_config_var_usage() {
	cat <<USAGE
...
List Configuration Variable Commands:
	list				Prints list of all variables.
	get <var> [<list>+]		Prints value of var for list(s).
	set <var> <value> [<list>+]	Sets value of var for list(s).
USAGE
}

m7_config_var_list() {
	local list=mailman
	local conf
	conf=$(list_config $list 'list.conf')
	run_sudo egrep "^[^ =]+ ?= " "$conf"
}

_m7_config_var_get() {
	local list=$1
	local conf
	conf=$(list_config $list 'list.conf')
	out=$(run_sudo egrep "^$var = " "$conf")
	if [ "$out" ]; then
		echo "$list: $out"
	fi
}
m7_config_var_get() {
	min_args 1 "$@"
	local var=$1
	shift
	for_each_list _m7_config_var_get "$@"
}

_m7_config_var_set() {
	local list=$1
	local conf
	conf=$(list_config $list 'list.conf')
	echo "$var = $value" >>"$conf"
	m7_config_check "$list"
	m7_config_set "$list"
}
m7_config_var_set() {
	min_args 2 "$@"
	local var=$1
	local value=$2
	shift 2
	for_each_list _m7_config_var_set "$@"
}


######
# Main

m7_desc() { echo "Mailman management tool"; }

m7_usage() {
	cat <<USAGE
<cmd> ...
Mailing List Commands:
	list ...			List query commands
	config ...			List configuration commands
	passwd ...			List password commands

List Management Commands:
	new <list> [<domain>]		Creates a new mailing list
	rename <cmd> <old> <new>	Renames a mailing list
	delete <list>			Deletes a mailing list
USAGE
}

m7_help() {
	cat<<HELP
The $script_name tool manages and assists with mailman list creation, bulk site
reconfiguration, and similar tasks.
HELP
}

app_run "$@"

View the Developer Guide Index

View the Reference Manual Index


Generated on Fri Jul 28 14:34:35 PDT 2017 by mcsh d14 v0.23.0.