vmail-stack/bin/vmail.sh
2023-10-09 16:35:30 -07:00

237 lines
6.5 KiB
Bash
Executable File

#!/bin/bash
#
# vmail-stack
# https://git.stack-source.com/msb/vmail-stack
# Copyright (c) 2022 Matthew Saunders Brown <matthewsaundersbrown@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
# vmail include file, used by other vmail bash scripts
# constants
readonly VMAIL_DIR=/var/vmail
readonly MYSQL_CONNECTION_INFO_FILE=$VMAIL_DIR/.my.cnf
# switch to required user
if [[ $(basename $0) == "vmail-domains-arc.sh" ]] || [[ $(basename $0) == "vmail-domains-exp.sh" ]] || [[ $(basename $0) == "vmail-domains-imp.sh" ]] || [[ $(basename $0) == "vmail-dovecot-"* ]]; then
if [[ "$USER" != "root" ]]; then
exec sudo -u root $0 "$@"
fi
elif [[ $(basename $0) == "vmail-dkim-"* ]]; then
if [[ "$USER" != "Debian-exim" ]]; then
exec sudo -u Debian-exim -g ssl-cert $0 "$@"
fi
elif [[ $(basename $0) == "vmail-purge-spool.sh" ]]; then
if [[ "$USER" != "Debian-exim" ]]; then
exec sudo -u Debian-exim $0 "$@"
fi
else
if [[ "$USER" != "vmail" ]]; then
exec sudo -u vmail $0 "$@"
else
# check that MYSQL_CONNECTION_INFO_FILE exists and is readable
if [ ! -f "$MYSQL_CONNECTION_INFO_FILE" ]; then
echo "ERROR: MySQL connection info file ($MYSQL_CONNECTION_INFO_FILE) does not exist or is not readable."
exit 1
fi
fi
fi
# functions
# crude but good enough domain name format validation
function vmail::validate_domain () {
local my_domain=$1
if [[ $my_domain =~ ^(([a-zA-Z0-9](-?[a-zA-Z0-9])*)\.)+[a-zA-Z]{2,}$ ]] ; then
return 0
else
return 1
fi
}
# yesno prompt
#
# Examples:
# loop until y or n: if vmail::yesno "Continue?"; then
# default y: if vmail::yesno "Continue?" Y; then
# default n: if vmail::yesno "Continue?" N; then
function vmail::yesno() {
local prompt default reply
if [ "${2:-}" = "Y" ]; then
prompt="Y/n"
default=Y
elif [ "${2:-}" = "N" ]; then
prompt="y/N"
default=N
else
prompt="y/n"
default=
fi
while true; do
read -p "$1 [$prompt] " -n 1 -r reply
# Default?
if [ -z "$reply" ]; then
reply=$default
fi
# Check if the reply is valid
case "$reply" in
Y*|y*) return 0 ;;
N*|n*) return 1 ;;
esac
done
}
function vmail:getoptions () {
local OPTIND
while getopts "ha:b:d:e:f:gj:cp:q:r:s:tk:gl:m:o:u:vx" opt ; do
case "${opt}" in
h ) # display help and exit
help
exit
;;
a ) # alias
alias=${OPTARG,,}
if [[ $alias =~ "@" ]] ; then
domain=${alias##*@}
if vmail::validate_domain $domain; then
alias=${alias%@*}
else
echo "ERROR: $domain is not a valid domain name."
exit 1
fi
fi
;;
b ) # body - Body for Autoresponder emails
body="${OPTARG}"
;;
c ) # cvs - output in cvs format
cvs="| sed 's/\t/,/g'"
;;
d ) # domain name (virtualhost) to act on
domain=${OPTARG,,}
if ! vmail::validate_domain $domain; then
echo "ERROR: $domain is not a valid domain name."
exit 1
fi
;;
e ) # email address
email=${OPTARG,,}
if [[ $email =~ "@" ]] ; then
mbox=${email%@*}
domain=${email##*@}
if [ -z $mbox ] ; then
echo "ERROR: No local part in $email."
exit 1
elif [ -z $domain ] ; then
echo "ERROR: No domain in $email."
exit 1
elif ! vmail::validate_domain $domain; then
echo "ERROR: $domain is not a valid domain name."
exit 1
fi
else
echo "ERROR: $email is not a valid email."
exit 1
fi
;;
f ) # forward to email address
forward=${OPTARG,,}
if [[ $forward =~ "@" ]] ; then
forward_mbox=${forward%@*}
forward_domain=${forward##*@}
if [ -z $forward_mbox ] ; then
echo "ERROR: No local part in $forward."
exit 1
elif [ -z $forward_domain ] ; then
echo "ERROR: No domain in $forward."
exit 1
elif ! vmail::validate_domain $forward_domain; then
echo "ERROR: $forward_domain is not a valid domain name."
exit 1
fi
else
echo "ERROR: $forward is not a valid email."
exit 1
fi
;;
g ) # glob (wildcard) search
glob=${OPTARG,,}
;;
j ) # Filter Junk
filter=${OPTARG}
;;
k ) # keep
keep=${OPTARG}
if [[ $keep != "0" ]] && [[ $keep != "1" ]]; then
echo "ERROR: Invalid save keep setting: -k $keep."
exit 1
fi
;;
l ) # limit
limit=${OPTARG}
;;
m ) # mbox
mbox=${OPTARG}
;;
p ) # password
password=${OPTARG}
;;
o ) # mode for autoresponder - must be Vacation or Autoresponder
mode=${OPTARG,,} # first force lower case
mode=${mode^} # then capitlize first letter
if [[ $mode != "Vacation" ]] && [[ $mode != "Autoresponder" ]]; then
echo "ERROR: Invalid mode setting: -o $mode. Must be either Vacation or Autoresponder"
exit 1
fi
;;
q ) # quota
quota=${OPTARG}
;;
r ) # ratelimit - hourly limit for sending, multiplied by 10 for daily limit
ratelimit=${OPTARG}
;;
s ) # status - 0 or 1 or 2
status=${OPTARG}
if [[ $status != "0" ]] && [[ $status != "1" ]] && [[ $status != "2" ]]; then
echo "ERROR: Invalid status setting: -s $status"
exit 1
fi
;;
t ) # tab - Use tabs instead of tables for output, do not display column headers
tab=true
;;
u ) # subject - Subject for Autoresponder emails
subject="${OPTARG}"
;;
n ) # dry-run
dryrun=true
;;
v ) # verbose
verbose=true
;;
w ) # write - store data in file
write=true
;;
x ) # eXecute - don't prompt for confirmation
execute=true
;;
\? )
echo "Invalid option: $OPTARG"
exit 1
;;
: )
echo "Invalid option: $OPTARG requires an argument"
exit 1
;;
esac
done
shift $((OPTIND-1))
}