#!/bin/bash # Wrapper for various setup scripts # included in the docker-mailserver set -euEo pipefail trap '_report_err $_ $LINENO $?' ERR function _report_err() { echo "ERROR occured :: source (hint) $1 ; line $2 ; exit code $3 ;;" >&2 _unset_vars } function _unset_vars() { unset CDIR CRI INFO IMAGE_NAME CONTAINER_NAME DEFAULT_CONFIG_PATH unset USE_CONTAINER WISHED_CONFIG_PATH CONFIG_PATH VOLUME USE_TTY } CDIR="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" CRI= INFO= IMAGE_NAME= CONTAINER_NAME='mail' DEFAULT_CONFIG_PATH="$CDIR/config" USE_CONTAINER=false WISHED_CONFIG_PATH= CONFIG_PATH= VOLUME= USE_TTY= function _check_root() { if [[ $EUID -ne 0 ]] then echo "Curently docker-mailserver doesn't support podman's rootless mode, please run this script as root user." return 1 fi } function _update_config_path() { if [[ -n $CONTAINER_NAME ]] then VOLUME=$(docker inspect "$CONTAINER_NAME" \ --format="{{range .Mounts}}{{ println .Source .Destination}}{{end}}" | \ grep "/tmp/docker-mailserver$" 2>/dev/null) fi if [[ -n $VOLUME ]] then CONFIG_PATH=$(echo "$VOLUME" | awk '{print $1}') fi } function _inspect() { if _docker_image_exists "$IMAGE_NAME" then echo "Image: $IMAGE_NAME" else echo "Image: '$IMAGE_NAME' can’t be found." fi if [[ -n $CONTAINER_NAME ]] then echo "Container: $CONTAINER_NAME" echo "Config mount: $CONFIG_PATH" else echo "Container: Not running, please start docker-mailserver." fi } function _usage() { echo "Usage: $0 [-i IMAGE_NAME] [-c CONTAINER_NAME] [args] OPTIONS: -i IMAGE_NAME The name of the docker-mailserver image, by default 'tvial/docker-mailserver:latest' for docker, and 'docker.io/tvial/docker-mailserver:latest' for podman. -c CONTAINER_NAME The name of the running container. -p PATH config folder path (default: $(pwd)/config) SUBCOMMANDS: email: $0 email add [] $0 email update [] $0 email del $0 email restrict [] $0 email list alias: $0 alias add $0 alias del $0 alias list quota: $0 quota set [] $0 quota del config: $0 config dkim (default: 2048) $0 config ssl relay: $0 relay add-domain [] $0 relay add-auth [] $0 relay exclude-domain debug: $0 debug fetchmail $0 debug fail2ban [ ] $0 debug show-mail-logs $0 debug inspect $0 debug login " return 1 } function _docker_image_exists() { if $CRI history -q "$1" >/dev/null 2>&1 then return 0 else return 1 fi } function _docker_image() { if $USE_CONTAINER then # reuse existing container specified on command line $CRI exec "$USE_TTY" "$CONTAINER_NAME" "$@" else # start temporary container with specified image if ! _docker_image_exists "$IMAGE_NAME" then echo "Image '$IMAGE_NAME' not found. Pulling ..." $CRI pull "$IMAGE_NAME" fi ${CRI} run --rm \ -v "$CONFIG_PATH":/tmp/docker-mailserver \ "$USE_TTY" "$IMAGE_NAME" "$@" fi } function _docker_container() { if [[ -n $CONTAINER_NAME ]] then $CRI exec "$USE_TTY" "$CONTAINER_NAME" "$@" else echo "The docker-mailserver is not running!" exit 1 fi } function _main() { if [[ -n $(command -v docker) ]] then CRI=docker elif [[ -n $(command -v podman) ]] then CRI=podman _check_root else echo "No supported Container Runtime Interface detected." exit 10 fi INFO=$($CRI ps \ --no-trunc \ --format "{{.Image}};{{.Names}}" \ --filter label=org.label-schema.name="docker-mailserver" | \ tail -1) IMAGE_NAME=${INFO%;*} CONTAINER_NAME=${INFO#*;} if [[ -z $IMAGE_NAME ]] then if [[ $CRI == "docker" ]] then IMAGE_NAME=tvial/docker-mailserver:latest elif [[ $CRI == "podman" ]] then IMAGE_NAME=docker.io/tvial/docker-mailserver:latest fi fi if tty -s then USE_TTY="-ti" fi local OPTIND while getopts ":c:i:p:" OPT do case $OPT in c) CONTAINER_NAME="$OPTARG" ; USE_CONTAINER=true ;; # container specified, connect to running instance i) IMAGE_NAME="$OPTARG" ;; p) case "$OPTARG" in /*) WISHED_CONFIG_PATH="$OPTARG" ;; * ) WISHED_CONFIG_PATH="$CDIR/$OPTARG" ;; esac if [[ ! -d $WISHED_CONFIG_PATH ]] then echo "Directory doesn't exist" _usage exit 1 fi ;; *) echo "Invalid option: -$OPTARG" >&2 ;; esac done shift $((OPTIND-1)) if [[ -z $WISHED_CONFIG_PATH ]] then # no wished config path _update_config_path if [[ -z $CONFIG_PATH ]] then CONFIG_PATH=$DEFAULT_CONFIG_PATH fi else CONFIG_PATH=$WISHED_CONFIG_PATH fi case ${1:-} in email) shift ; case ${1:-} in add ) shift ; _docker_image addmailuser "$@" ;; update ) shift ; _docker_image updatemailuser "$@" ;; del ) shift ; _docker_image delmailuser "$@" ;; restrict ) shift ; _docker_container restrict-access "$@" ;; list ) _docker_image listmailuser ;; * ) _usage ;; esac ;; alias) shift ; case ${1:-} in add ) shift ; _docker_image addalias "$@" ;; del ) shift ; _docker_image delalias "$@" ;; list ) shift ; _docker_image listalias "$@" ;; * ) _usage ;; esac ;; quota) shift ; case ${1:-} in set ) shift ; _docker_image setquota "$@" ;; del ) shift ; _docker_image delquota "$@" ;; * ) _usage ;; esac ;; config) shift ; case ${1:-} in dkim ) _docker_image generate-dkim-config "${2:-2048}" ;; ssl ) _docker_image generate-ssl-certificate "$2" ;; * ) _usage ;; esac ;; relay) shift ; case ${1:-} in add-domain ) shift ; _docker_image addrelayhost "$@" ;; add-auth ) shift ; _docker_image addsaslpassword "$@" ;; exclude-domain ) shift ; _docker_image excluderelaydomain "$@" ;; * ) _usage ;; esac ;; debug) shift ; case ${1:-} in fetchmail ) _docker_image debug-fetchmail ;; fail2ban ) shift ; _docker_container fail2ban "$@" ;; show-mail-logs ) _docker_container cat /var/log/mail/mail.log ;; inspect ) _inspect ;; login ) shift if [[ -z ${1:-''} ]] then _docker_container /bin/bash else _docker_container /bin/bash -c "$@" fi ;; * ) _usage ;; esac ;; * ) _usage ;; esac } _main "$@" _unset_vars