Files
mailsystem/install_update_dovecot-2.4.sh

7995 lines
233 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
## ===================================================================
## - Install/Update Dovecot Server
## ===================================================================
## -----------------------------------------------------------------
## ----------------------------------------------------------------
## ---
## --- For configurations see file conf/install_update_dovecot.conf
## ---
## --- Dont make changes here!
## ---
## -----------------------------------------------------------------
## -----------------------------------------------------------------
# -------------
# - Settings
# -------------
_src_base_dir="$(realpath $(dirname $0))"
conf_file="${_src_base_dir}/conf/install_update_dovecot.conf"
curdir=`pwd`
log_file="$(mktemp)"
backup_date="$(date +%Y-%m-%d-%H%M)"
_backup_crontab_file="/tmp/crontab_root.${backup_date}"
rc_done="\033[71G[ \033[32mdone\033[m ]"
rc_failed="\033[71G[ \033[31m\033[1mfailed\033[m ]"
#rc_skipped="\033[71G[ \033[33m\033[1mskipped\033[m ]"
rc_skipped="\033[71G[ \033[1;37mskipped\033[m ]"
rc_wait="\033[71G[ \033[5m\033[1m..\033[m ]"
rc_not_yet_implemented="\033[71G[ \033[1;33mNot Yet Implemented\033[m ]"
# -------------
# - Functions an Variable
# -------------
clean_up() {
if [[ -f "$_backup_crontab_file" ]]; then
echononl "(Re)Install previously saved crontab from '$_backup_crontab_file'.."
crontab $_backup_crontab_file >> $log_file 2>&1
if [[ $? -eq 0 ]]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "$(cat $log_file)"
fi
fi
# Perform program exit housekeeping
rm -f $log_file
blank_line
exit $1
}
echononl(){
echo X\\c > /tmp/shprompt$$
if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then
echo -e "$*\\c" 1>&2
else
echo -en "$*" 1>&2
fi
rm /tmp/shprompt$$
}
fatal(){
echo ""
echo -e "\t[ \033[31m\033[1mFatal\033[m ]: \033[37m\033[1m$*\033[m"
echo ""
echo -e "\t\033[31m\033[1m Skript wird abgebrochen\033[m\033[m\n"
rm -f $log_file
clean_up 1
}
error(){
echo ""
echo -e "\t[ \033[31m\033[1mError\033[m ]: $*"
echo ""
}
warn(){
echo ""
echo -e "\t[ \033[33m\033[1mWarning\033[m ]: $*"
echo ""
}
info(){
echo ""
echo -e "\t[ \033[32m\033[1mInfo\033[m ]: $*"
echo ""
}
blank_line() {
echo ""
}
echo_ok() {
echo -e "\033[71G[ \033[32mok\033[m ]"
}
echo_failed(){
echo -e "\033[71G[ \033[1;31mfailed\033[m ]"
}
echo_skipped() {
echo -e "\033[71G[ \033[33m\033[1mskipped\033[m ]"
}
detect_os_1 () {
if $(which lsb_release > /dev/null 2>&1) ; then
os_dist="$(lsb_release -i | awk '{print tolower($3)}')"
os_version="$(lsb_release -r | awk '{print tolower($2)}')"
os_codename="$(lsb_release -c | awk '{print tolower($2)}')"
if [[ "$os_dist" = "debian" ]]; then
if $(echo "$os_version" | grep -q '\.') ; then
os_version=$(echo "$os_version" | cut --delimiter='.' -f1)
fi
fi
elif [[ -e "/etc/os-release" ]]; then
. /etc/os-release
os_dist=$ID
os_version=${VERSION_ID}
fi
# remove whitespace from os_dist and os_version
os_dist="${os_dist// /}"
os_version="${os_version// /}"
}
replace_code_block() {
local block_name="$1"
local new_block="$2"
local file="$3"
if [[ -z "$block_name" || -z "$new_block" || -z "$file" ]]; then
echo "Fehler: Parameter fehlen."
echo "Verwendung: replace_dovecot_block \"blockname\" \"neuer_block\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Fehler: Datei '$file' existiert nicht."
return 1
fi
local tmp_file
tmp_file=$(mktemp)
awk -v block_name="$block_name" -v new_block="$new_block" '
function count_char(str, c) {
n = 0
for (i = 1; i <= length(str); i++) {
if (substr(str, i, 1) == c) n++
}
return n
}
{
if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") {
in_block = 1
brace_depth = count_char($0, "{") - count_char($0, "}")
print new_block
next
}
if (in_block) {
brace_depth += count_char($0, "{") - count_char($0, "}")
if (brace_depth <= 0) {
in_block = 0
}
next
}
print
}
' "$file" > "$tmp_file"
mv "$tmp_file" "$file"
return 0
}
replace_or_append_code_block() {
local block_name="$1"
local new_block="$2"
local file="$3"
if [[ -z "$block_name" || -z "$new_block" || -z "$file" ]]; then
echo "Fehler: Parameter fehlen."
echo "Verwendung: replace_dovecot_block \"blockname\" \"neuer_block\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Fehler: Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
local block_found=0
awk -v block_name="$block_name" -v new_block="$new_block" '
function count_char(str, c) {
n = 0
for (i = 1; i <= length(str); i++) {
if (substr(str, i, 1) == c) n++
}
return n
}
{
if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") {
in_block = 1
brace_depth = count_char($0, "{") - count_char($0, "}")
print new_block
block_found = 1
next
}
if (in_block) {
brace_depth += count_char($0, "{") - count_char($0, "}")
if (brace_depth <= 0) {
in_block = 0
}
next
}
print
}
END {
if (!block_found) {
print new_block > "/dev/stderr"
exit 3
}
}
' "$file" 1>"$tmp_file" 2>_new_block_to_append.tmp
result=$?
if [[ $result -eq 3 ]]; then
# Block nicht gefunden neuen Block anhängen
echo "" >> "$file"
cat _new_block_to_append.tmp >> "$file"
rm -f "$tmp_file" _new_block_to_append.tmp
echo "Block '$block_name' wurde nicht gefunden und deshalb am Ende der Datei angehängt."
return 0
fi
mv "$tmp_file" "$file"
rm -f _new_block_to_append.tmp
echo "Block '$block_name' wurde ersetzt."
return 0
}
replace_or_append_code_block_if_keyval() {
local block_name="$1"
local new_block="$2"
local file="$3"
local required_key="$4"
local required_value="$5"
if [[ -z "$block_name" || -z "$new_block" || -z "$file" || -z "$required_key" || -z "$required_value" ]]; then
echo "Fehler: Parameter fehlen."
echo "Verwendung: replace_or_append_code_block_if_keyval \"blockname\" \"neuer_block\" \"/pfad/zur/datei\" \"key\" \"value\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Fehler: Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
local block_found=0
awk -v block_name="$block_name" -v new_block="$new_block" \
-v req_key="$required_key" -v req_val="$required_value" '
function count_char(str, c) {
n = 0
for (i = 1; i <= length(str); i++) {
if (substr(str, i, 1) == c) n++
}
return n
}
{
if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") {
in_block = 1
brace_depth = count_char($0, "{") - count_char($0, "}")
block_buffer = $0 "\n"
found_keyval = 0
next
}
if (in_block) {
brace_depth += count_char($0, "{") - count_char($0, "}")
block_buffer = block_buffer $0 "\n"
# Prüfe nur im obersten Block-Level auf key = value
if (brace_depth == 1 && $0 ~ "^\\s*" req_key "\\s*=\\s*" req_val "\\s*$") {
found_keyval = 1
}
if (brace_depth <= 0) {
in_block = 0
if (found_keyval) {
print new_block
block_found = 1
} else {
printf "%s", block_buffer
}
next
}
next
}
print
}
END {
if (!block_found) {
print new_block > "/dev/stderr"
exit 3
}
}
' "$file" 1>"$tmp_file" 2>_new_block_to_append.tmp
result=$?
if [[ $result -eq 3 ]]; then
echo "" >> "$file"
cat _new_block_to_append.tmp >> "$file"
rm -f "$tmp_file" _new_block_to_append.tmp
echo "Block '$block_name' wurde nicht gefunden oder Bedingung nicht erfüllt daher am Ende angehängt."
return 0
fi
mv "$tmp_file" "$file"
rm -f _new_block_to_append.tmp
echo "Block '$block_name' wurde ersetzt (Bedingung erfüllt)."
return 0
}
delete_code_block() {
local block_name="$1"
local file="$2"
if [[ -z "$block_name" || -z "$file" ]]; then
echo "Verwendung: delete_block \"blockname\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
awk -v block_name="$block_name" '
function count_char(str, c) {
n = 0
for (i = 1; i <= length(str); i++) {
if (substr(str, i, 1) == c) n++
}
return n
}
{
if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") {
in_block = 1
brace_depth = count_char($0, "{") - count_char($0, "}")
next
}
if (in_block) {
brace_depth += count_char($0, "{") - count_char($0, "}")
if (brace_depth <= 0) {
in_block = 0
}
next
}
print
}
' "$file" > "$tmp_file"
mv "$tmp_file" "$file"
echo "Block '$block_name' wurde gelöscht."
return 0
}
delete_code_block_with_comments() {
local block_name="$1"
local file="$2"
if [[ -z "$block_name" || -z "$file" ]]; then
echo "Verwendung: delete_block_with_comments \"blockname\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
awk -v block_name="$block_name" '
function count_char(str, c) {
n = 0
for (i = 1; i <= length(str); i++) {
if (substr(str, i, 1) == c) n++
}
return n
}
{
lines[NR] = $0
if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") {
# Rückwärts prüfen, ob vorherige Zeilen nur Kommentare oder leer sind
start = NR
for (i = NR - 1; i >= 1; i--) {
if (lines[i] ~ /^#|^\s*$/) {
start = i
} else {
break
}
}
in_block = 1
brace_depth = count_char($0, "{") - count_char($0, "}")
skip_until = NR
next
}
if (in_block) {
brace_depth += count_char($0, "{") - count_char($0, "}")
if (brace_depth <= 0) {
in_block = 0
for (i = start; i <= NR; i++) {
deleted[i] = 1
}
}
next
}
}
END {
for (i = 1; i <= NR; i++) {
if (!(i in deleted)) {
print lines[i]
}
}
}
' "$file" > "$tmp_file"
mv "$tmp_file" "$file"
echo "Block '$block_name' inkl. vorangehender Kommentare wurde gelöscht."
return 0
}
replace_variable() {
local var_name="$1"
local new_value="$2"
local file="$3"
if [[ -z "$var_name" || -z "$new_value" || -z "$file" ]]; then
echo "Verwendung: replace_variable \"variablenname\" \"neuer_wert\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
awk -v var_name="$var_name" -v new_value="$new_value" '
BEGIN {
replaced = 0
}
{
if ($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^[:alnum:]#])") {
# Ersetze gesamte Zeile durch normierte Form
print var_name " = " new_value
replaced = 1
} else {
print
}
}
END {
if (!replaced) {
print var_name " = " new_value > "/dev/stderr"
exit 3
}
}
' "$file" 1> "$tmp_file" 2> _missing_var.tmp
result=$?
if [[ $result -eq 3 ]]; then
# Variable nicht gefunden → neue hinzufügen
echo "" >> "$file"
cat _missing_var.tmp >> "$file"
echo " Variable '$var_name' wurde neu ans Ende angehängt."
rm -f "$tmp_file" _missing_var.tmp
return 0
fi
mv "$tmp_file" "$file"
rm -f _missing_var.tmp
echo "Variable '$var_name' wurde ersetzt."
return 0
}
replace_or_append_variable() {
local var_name="$1"
local new_value="$2"
local file="$3"
if [[ -z "$var_name" || -z "$new_value" || -z "$file" ]]; then
echo "Verwendung: replace_variable \"variablenname\" \"neuer_wert\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
awk -v var_name="$var_name" -v new_value="$new_value" '
BEGIN { replaced = 0 }
{
if ($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^[:alnum:]#])") {
print var_name " = " new_value
replaced = 1
} else {
print
}
}
END {
if (!replaced) {
printf("\n%s = %s\n", var_name, new_value) >> "/dev/stderr"
exit 3
}
}
' "$file" > "$tmp_file" 2> _var_append.tmp
result=$?
if [[ $result -eq 3 ]]; then
cat _var_append.tmp >> "$tmp_file"
echo "Variable '$var_name' wurde neu ans Ende angehängt."
else
echo "Variable '$var_name' wurde ersetzt."
fi
mv "$tmp_file" "$file"
rm -f _var_append.tmp
return 0
}
delete_variable() {
local var_name="$1"
local file="$2"
if [[ -z "$var_name" || -z "$file" ]]; then
echo "Verwendung: delete_variable_only \"variablenname\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
awk -v var_name="$var_name" '
# match: key = val, key=val, key val
!($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^[:alnum:]#])") {
print
}
' "$file" > "$tmp_file"
mv "$tmp_file" "$file"
echo "Nur Variable '$var_name' wurde gelöscht (Kommentare erhalten)."
return 0
}
delete_variable_with_comments() {
local var_name="$1"
local file="$2"
if [[ -z "$var_name" || -z "$file" ]]; then
echo "Verwendung: delete_variable_with_comments \"variablenname\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
awk -v var_name="$var_name" '
{
lines[NR] = $0
if ($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^=[:alnum:]])") {
# Rückwärts: vorangehende Kommentarzeilen (ohne Leerzeile)
start = NR
for (i = NR - 1; i >= 1; i--) {
if (lines[i] ~ /^[[:space:]]*#/) {
start = i
} else if (lines[i] ~ /^[[:space:]]*$/) {
break
} else {
break
}
}
for (i = start; i <= NR; i++) {
delete lines[i]
}
}
}
END {
for (i = 1; i <= NR; i++) {
if (i in lines) {
print lines[i]
}
}
}
' "$file" > "$tmp_file"
mv "$tmp_file" "$file"
echo "Variable '$var_name' inkl. zugehöriger Kommentare wurde gelöscht."
return 0
}
# - Support systemd ?
# -
if [[ "X$(which systemd)" = "X" ]]; then
SYSTEMD_EXISTS=false
else
SYSTEMD_EXISTS=true
fi
if [[ -f "/usr/local/mysql/sys-maint.cnf" ]] ; then
DEFAULT_MYSQL_CREDENTIALS="--defaults-file=/usr/local/mysql/sys-maint.cnf"
elif [[ -f "/etc/mysql/debian.cnf" ]] ; then
DEFAULT_MYSQL_CREDENTIALS="--defaults-file=/etc/mysql/debian.cnf"
else
DEFAULT_MYSQL_CREDENTIALS=""
fi
DEFAULT_SSL_CIPHER_LIST="ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305"
DEFAULT_VMAIL_UID=5000
DEFAULT_VMAIL_GID=5000
# - Detect OS - Set variable
# - os_dist
# - os_version
# - os_codename
# -
detect_os_1
echo
echononl " Include Configuration file.."
if [[ ! -f $conf_file ]]; then
echo -e "$rc_failed"
fatal "Missing configuration file '$conf_file'"
else
source $conf_file
echo -e "$rc_done"
fi
if [[ -z "$systemd_support" ]] ; then
if $SYSTEMD_EXISTS ; then
systemd_support=true
else
systemd_support=false
fi
fi
## - Required parameters
## -
[[ -n "$_update" ]] || fatal "Parameter "_update" not set."
[[ -n "$postmaster_address" ]] || postmaster_address="argus\@oopen.de"
[[ -n "$hostname" ]] || fatal "Missing value for parameter 'hostname'."
[[ -n "$ipv4" ]] || fatal "Missing value for parameter 'ipv4'."
[[ -n "$ipv6" ]] || warn "Missing value for parameter 'ipv6'."
[[ -n "$database" ]] || fatal "Parameter "database" not set."
if [[ "$database" != "postgres" ]] && [[ "$database" != "mysql" ]] ; then
fatal "Wrong value for parameter 'database' ({$database}). Only 'mysql' or 'postgres' is allowed."
fi
[[ -n "$dbpassword" ]] || fatal "Parameter "dbpassword" not set."
[[ -n "$from_address" ]] || fatal ""Parameter "from_address" not set.""
[[ -n "$reply_to" ]] || fatal ""Parameter "reply_to" not set.""
[[ -n "$webmailer" ]] || fatal ""Parameter "webmailer" not set.""
[[ -n "$salutation" ]] || fatal ""Parameter "salutation" not set.""
## - Some defaults if missing
## -
if [[ -n "$ipv6" ]] ; then
[[ -n "$imap_listener_adresses" ]] || imap_listener_adresses="127.0.0.1 $ipv4 $ipv6"
[[ -n "$imaps_listener_adresses" ]] || imaps_listener_adresses="127.0.0.1 $ipv4 $ipv6"
[[ -n "$pop_listener_adresses" ]] || pop_listener_adresses="$ipv4 $ipv6"
[[ -n "$pops_listener_adresses" ]] || pops_listener_adresses="127.0.0.1 $ipv4 $ipv6"
else
[[ -n "$imap_listener_adresses" ]] || imap_listener_adresses="127.0.0.1 $ipv4"
[[ -n "$imaps_listener_adresses" ]] || imaps_listener_adresses="127.0.0.1 $ipv4"
[[ -n "$pop_listener_adresses" ]] || pop_listener_adresses="$ipv4"
[[ -n "$pops_listener_adresses" ]] || pops_listener_adresses="127.0.0.1 $ipv4"
fi
[[ -n "$xmpp_listener" ]] || xmpp_listener=false
if $xmpp_listener ; then
# Be compartible with older installations
[[ -n "$xmpp_listener_address" ]] && xmpp_listener_addresses="$xmpp_listener_address"
[[ -n "$xmpp_listener_addresses" ]] || xmpp_listener_addresses="127.0.0.1 $ipv4"
[[ -n "$xmpp_listener_port" ]] || xmpp_listener_port="44444"
fi
[[ -n "$http_user" ]] || http_user="www-data"
[[ -n "$postfix_main_cf" ]] || postfix_main_cf="/etc/postfix/main.cf"
[[ -n "$dbname" ]] || dbname="postfix"
[[ -n "$dbuser" ]] || dbuser="postfix"
if [[ -z "$dbhost" ]] ; then
[[ "$database" = "mysql" ]] && dbhost="/run/mysqld/mysqld.sock"
[[ "$database" = "postgres" ]] && dbhost="/run/postgresql"
fi
[[ -n "$cert_base_dir" ]] || cert_base_dir="/etc/dovecot/ssl"
[[ -n "$server_cert" ]] || server_cert="${cert_base_dir}/mailserver.crt"
[[ -n "$server_key" ]] || server_key="${cert_base_dir}/mailserver.key"
[[ -n "$dh_pem_file" ]] || dh_pem_file="${cert_base_dir}/dh_4096.pem"
[[ -n "$ssl_cipher_list" ]] || ssl_cipher_list="${DEFAULT_SSL_CIPHER_LIST}"
[[ -n "$imap_cert" ]] || imap_cert="${cert_base_dir}/mailserver.crt"
[[ -n "$imap_key" ]] || imap_key="${cert_base_dir}/mailserver.key"
[[ -n "$pop_cert" ]] || pop_cert="${cert_base_dir}/mailserver.crt"
[[ -n "$pop_key" ]] || pop_key="${cert_base_dir}/mailserver.key"
[[ -n "$default_pass_scheme" ]] || default_pass_scheme="PLAIN"
[[ -n "$spam_folder" ]] || spam_folder="Spam"
[[ -n "$max_userip_connections" ]] || max_userip_connections=24
[[ -n "$auth_mechanisms" ]] || auth_mechanisms="plain login"
[[ -n "$service_limit_nofile" ]] || service_limit_nofile=524280
[[ -n "${vmail_uid}" ]] || vmail_uid=${DEFAULT_VMAIL_UID}
[[ -n "${vmail_gid}" ]] || vmail_gid=${DEFAULT_VMAIL_GID}
declare -i dovecot_major_version=0
declare -i dovecot_minor_version=0
declare -i dovecot_patch_level=0
echo -e "\033[32m--\033[m"
echo ""
echo "Version Number of Dovecot to install"
echo ""
echo ""
_version=
while [ "X$_version" = "X" ]
do
echononl "Dovecot Version: "
read _version
if [ "X$_version" = "X" ]; then
echo -e "\n\t\033[33m\033[1mA version number is required!\033[m\n"
fi
done
dovecot_main_version="$(echo $_version | cut -d '.' -f1,2)"
dovecot_major_version="$(echo $_version | cut -d '.' -f1)"
dovecot_minor_version="$(echo $_version | cut -d '.' -f2)"
dovecot_patch_level="$(echo $_version | cut -d '.' -f3)"
dovecot_minor_patch_level="$(echo $_version | cut -d '.' -f4)"
_version_short="${_version%-*}"
#echo ""
#echo "_version: $_version"
#echo "dovecot_main_version $dovecot_main_version"
#echo "dovecot_major_version $dovecot_major_version"
#echo "dovecot_minor_version $dovecot_minor_version"
#echo "dovecot_patch_level $dovecot_patch_level"
#echo "dovecot_minor_patch_level $dovecot_minor_patch_level"
#echo ""
#
#clean_up 0
# 'expire plugin'was removed in version 2.3.14: This plugin is not needed.
# Use mailbox { autoexpunge } Mailbox settings instead.
#
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] \
&& [[ $dovecot_minor_version -gt 3 ]] \
) \
|| ( [[ $dovecot_major_version -eq 2 ]] \
&& [[ $dovecot_minor_version -eq 3 ]] \
&& [[ $dovecot_patch_level -gt 13 ]] \
) ; then
plugin_expire=false
else
plugin_expire=true
fi
#if $plugin_expire ; then
# info "Install plugin 'expire'.."
#else
# warn "Plugin 'expire' is no longer supported.."
#fi
#exit 0
_log_dir=${_src_base_dir}/log-dovecot-$_version
if [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -lt 4 ]] ; then
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Version Number of Pigeonhole to install"
echo ""
echo ""
_pigeonhole=
while [ "X$_pigeonhole" = "X" ]
do
echononl "Pigeonhole Version: "
read _pigeonhole
if [ "X$_pigeonhole" = "X" ]; then
echo -e "\n\t\033[33m\033[1mA version number is required!\033[m\n"
fi
done
else
_pigeonhole=${_version}
fi
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Is this a fresh new installation or an update?"
echo ""
echo ""
if [[ -n "$_update" ]]; then
if $_update || [[ "${_update,,}" = 'yes' ]] ; then
echo -e "\033[37m\033[1m[1] Update\033[m"
echo "[2] New Installation"
else
echo -e "[1] Update"
echo -e "\033[37m\033[1m[2] New Installation\033[m"
fi
echo ""
echononl "Choose a number or press <RETURN> for highlighted value: "
else
echo -e "[1] Update"
echo "[2] New Installation"
echo ""
echononl "Choose a Number: "
fi
update=""
while [[ "$update" != "true" && "$update" != "false" ]] ; do
read OPTION
case $OPTION in
1) update=true
;;
2) update=false
;;
'') if [[ -n "$_update" ]] ; then
if $_update || [[ "${_update,,}" = 'yes' ]] ; then
update=true
else
update=false
fi
else
echo ""
echo -e "\tWrong entry! [ 1 = Update ; 2 = New Installation ]"
echo ""
echononl "Reentry: "
fi
;;
*) update=""
echo ""
if [[ -n "$_IS_RELAY_HOST" ]]; then
echo -e "\tWrong entry! [ 1 = Update ; 2 = New Installation ] or type <RETURN>"
else
echo -e "\tWrong entry! [ 1 = Update ; 2 = New Installation ]"
fi
echo ""
echononl "Reentry: "
;;
esac
done
# -------------
# - List Script Configurations
# -------------
clear;
echo ""
if $update ;then
echo -e "\tUpdate Dovecot................: $update"
else
echo -e "\tInstall Dovecot first time....: Yes"
fi
echo ""
echo -e "\tDovecot (new) version.........: $_version"
echo -e "\t(Sieve) pigeonhole version....: $_pigeonhole"
echo ""
echo -e "\tSystemd support...............: $systemd_support"
echo ""
echo -e "\tSFolder containing sources....: $_src_base_dir"
echo ""
echo -e "\tPostmaser adress..............: $postmaster_address"
echo -e "\tHostname......................: $hostname"
echo ""
echo -e "\tIPv4 address..................: $ipv4"
echo -e "\tIPv6 address..................: $ipv6"
echo ""
echo -e "\tIMAP listener addresses.......: $imap_listener_adresses"
echo -e "\tIMAPS listener addresses......: $imaps_listener_adresses"
echo ""
echo -e "\tPOP3 listener addresses.......: $pop_listener_adresses"
echo -e "\tPOP3S listener addresses......: $pops_listener_adresses"
echo ""
echo -e "\tPostfix Configuration File....: $postfix_main_cf"
echo ""
echo -e "\tDatenbank.....................: $database"
echo ""
echo -e "\tPostfix database host.........: $dbhost"
echo -e "\tPostfix database name.........: $dbname"
echo -e "\tPostfix database user.........: $dbuser"
echo -e "\tPostfix database password.....: $dbpassword"
echo ""
echo -e "\tDefault password scheme.......: $default_pass_scheme"
echo ""
echo -e "\tCertificat base directory.....: $cert_base_dir"
echo -e "\tServer certificate............: $server_cert"
echo -e "\tServer key....................: $server_key"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -ge 3 ]] ); then
echo -e "\tDH Parameters file............: $dh_pem_file"
fi
echo ""
echo -e "\tImap certificate..............: $imap_cert"
echo -e "\tImap key......................: $imap_key"
echo ""
echo -e "\tPop certificate...............: $pop_cert"
echo -e "\tPop key.......................: $pop_key"
echo ""
echo -e "\tSpan folder...................: $spam_folder"
echo -e "\tMax user connections per ip...: $max_userip_connections"
echo ""
echo -e "\tAuth Listener (Jabber)........: $xmpp_listener"
if $xmpp_listener ; then
echo -e "\t Auth Listener Addresses....: $xmpp_listener_addresses"
echo -e "\t AUTH Listener PORT.........: $xmpp_listener_port"
fi
echo ""
echo -e "\tInstall Plugin 'expire'.......: $plugin_expire"
echo ""
INSTALL_UPDATE_ENVIRONMENT_FILE="${_src_base_dir}/conf/install_update_dovecot-2.4..env"
cat <<EOF > ${INSTALL_UPDATE_ENVIRONMENT_FILE}
#!/usr/bin/env bash
log_file="${log_file}"
backup_date="${backup_date}"
_backup_crontab_file="${_backup_crontab_file}"
rc_done="${rc_done}"
rc_failed="${rc_failed}"
rc_skipped="${rc_skipped}"
rc_wait="${rc_wait}"
rc_not_yet_implemented="${rc_not_yet_implemented}"
EOF
cat <<'EOF' >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
# -------------
# - Functions an Variable
# -------------
clean_up() {
if [[ -f "$_backup_crontab_file" ]]; then
echononl "(Re)Install previously saved crontab from '$_backup_crontab_file'.."
crontab $_backup_crontab_file >> $log_file 2>&1
if [[ $? -eq 0 ]]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "$(cat $log_file)"
fi
fi
# Perform program exit housekeeping
rm -f $log_file
blank_line
exit $1
}
echononl(){
echo X\\c > /tmp/shprompt$$
if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then
echo -e "$*\\c" 1>&2
else
echo -en "$*" 1>&2
fi
rm /tmp/shprompt$$
}
fatal(){
echo ""
echo -e "\t[ \033[31m\033[1mFatal\033[m ]: \033[37m\033[1m$*\033[m"
echo ""
echo -e "\t\033[31m\033[1m Skript wird abgebrochen\033[m\033[m\n"
rm -f $log_file
clean_up 1
}
error(){
echo ""
echo -e "\t[ \033[31m\033[1mError\033[m ]: $*"
echo ""
}
warn(){
echo ""
echo -e "\t[ \033[33m\033[1mWarning\033[m ]: $*"
echo ""
}
info(){
echo ""
echo -e "\t[ \033[32m\033[1mInfo\033[m ]: $*"
echo ""
}
blank_line() {
echo ""
}
echo_ok() {
echo -e "\033[71G[ \033[32mok\033[m ]"
}
echo_failed(){
echo -e "\033[71G[ \033[1;31mfailed\033[m ]"
}
echo_skipped() {
echo -e "\033[71G[ \033[33m\033[1mskipped\033[m ]"
}
detect_os_1 () {
if $(which lsb_release > /dev/null 2>&1) ; then
os_dist="$(lsb_release -i | awk '{print tolower($3)}')"
os_version="$(lsb_release -r | awk '{print tolower($2)}')"
os_codename="$(lsb_release -c | awk '{print tolower($2)}')"
if [[ "$os_dist" = "debian" ]]; then
if $(echo "$os_version" | grep -q '\.') ; then
os_version=$(echo "$os_version" | cut --delimiter='.' -f1)
fi
fi
elif [[ -e "/etc/os-release" ]]; then
. /etc/os-release
os_dist=$ID
os_version=${VERSION_ID}
fi
# remove whitespace from os_dist and os_version
os_dist="${os_dist// /}"
os_version="${os_version// /}"
}
replace_code_block() {
local block_name="$1"
local new_block="$2"
local file="$3"
if [[ -z "$block_name" || -z "$new_block" || -z "$file" ]]; then
echo "Fehler: Parameter fehlen."
echo "Verwendung: replace_dovecot_block \"blockname\" \"neuer_block\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Fehler: Datei '$file' existiert nicht."
return 1
fi
local tmp_file
tmp_file=$(mktemp)
awk -v block_name="$block_name" -v new_block="$new_block" '
function count_char(str, c) {
n = 0
for (i = 1; i <= length(str); i++) {
if (substr(str, i, 1) == c) n++
}
return n
}
{
if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") {
in_block = 1
brace_depth = count_char($0, "{") - count_char($0, "}")
print new_block
next
}
if (in_block) {
brace_depth += count_char($0, "{") - count_char($0, "}")
if (brace_depth <= 0) {
in_block = 0
}
next
}
print
}
' "$file" > "$tmp_file"
mv "$tmp_file" "$file"
return 0
}
replace_or_append_code_block() {
local block_name="$1"
local new_block="$2"
local file="$3"
if [[ -z "$block_name" || -z "$new_block" || -z "$file" ]]; then
echo "Fehler: Parameter fehlen."
echo "Verwendung: replace_dovecot_block \"blockname\" \"neuer_block\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Fehler: Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
local block_found=0
awk -v block_name="$block_name" -v new_block="$new_block" '
function count_char(str, c) {
n = 0
for (i = 1; i <= length(str); i++) {
if (substr(str, i, 1) == c) n++
}
return n
}
{
if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") {
in_block = 1
brace_depth = count_char($0, "{") - count_char($0, "}")
print new_block
block_found = 1
next
}
if (in_block) {
brace_depth += count_char($0, "{") - count_char($0, "}")
if (brace_depth <= 0) {
in_block = 0
}
next
}
print
}
END {
if (!block_found) {
print new_block > "/dev/stderr"
exit 3
}
}
' "$file" 1>"$tmp_file" 2>_new_block_to_append.tmp
result=$?
if [[ $result -eq 3 ]]; then
# Block nicht gefunden neuen Block anhängen
echo "" >> "$file"
cat _new_block_to_append.tmp >> "$file"
rm -f "$tmp_file" _new_block_to_append.tmp
echo "Block '$block_name' wurde nicht gefunden und deshalb am Ende der Datei angehängt."
return 0
fi
mv "$tmp_file" "$file"
rm -f _new_block_to_append.tmp
echo "Block '$block_name' wurde ersetzt."
return 0
}
replace_or_append_code_block_if_keyval() {
local block_name="$1"
local new_block="$2"
local file="$3"
local required_key="$4"
local required_value="$5"
if [[ -z "$block_name" || -z "$new_block" || -z "$file" || -z "$required_key" || -z "$required_value" ]]; then
echo "Fehler: Parameter fehlen."
echo "Verwendung: replace_or_append_code_block_if_keyval \"blockname\" \"neuer_block\" \"/pfad/zur/datei\" \"key\" \"value\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Fehler: Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
local block_found=0
awk -v block_name="$block_name" -v new_block="$new_block" \
-v req_key="$required_key" -v req_val="$required_value" '
function count_char(str, c) {
n = 0
for (i = 1; i <= length(str); i++) {
if (substr(str, i, 1) == c) n++
}
return n
}
{
if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") {
in_block = 1
brace_depth = count_char($0, "{") - count_char($0, "}")
block_buffer = $0 "\n"
found_keyval = 0
next
}
if (in_block) {
brace_depth += count_char($0, "{") - count_char($0, "}")
block_buffer = block_buffer $0 "\n"
# Prüfe nur im obersten Block-Level auf key = value
if (brace_depth == 1 && $0 ~ "^\\s*" req_key "\\s*=\\s*" req_val "\\s*$") {
found_keyval = 1
}
if (brace_depth <= 0) {
in_block = 0
if (found_keyval) {
print new_block
block_found = 1
} else {
printf "%s", block_buffer
}
next
}
next
}
print
}
END {
if (!block_found) {
print new_block > "/dev/stderr"
exit 3
}
}
' "$file" 1>"$tmp_file" 2>_new_block_to_append.tmp
result=$?
if [[ $result -eq 3 ]]; then
echo "" >> "$file"
cat _new_block_to_append.tmp >> "$file"
rm -f "$tmp_file" _new_block_to_append.tmp
echo "Block '$block_name' wurde nicht gefunden oder Bedingung nicht erfüllt daher am Ende angehängt."
return 0
fi
mv "$tmp_file" "$file"
rm -f _new_block_to_append.tmp
echo "Block '$block_name' wurde ersetzt (Bedingung erfüllt)."
return 0
}
delete_code_block() {
local block_name="$1"
local file="$2"
if [[ -z "$block_name" || -z "$file" ]]; then
echo "Verwendung: delete_block \"blockname\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
awk -v block_name="$block_name" '
function count_char(str, c) {
n = 0
for (i = 1; i <= length(str); i++) {
if (substr(str, i, 1) == c) n++
}
return n
}
{
if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") {
in_block = 1
brace_depth = count_char($0, "{") - count_char($0, "}")
next
}
if (in_block) {
brace_depth += count_char($0, "{") - count_char($0, "}")
if (brace_depth <= 0) {
in_block = 0
}
next
}
print
}
' "$file" > "$tmp_file"
mv "$tmp_file" "$file"
echo "Block '$block_name' wurde gelöscht."
return 0
}
replace_variable() {
local var_name="$1"
local new_value="$2"
local file="$3"
if [[ -z "$var_name" || -z "$new_value" || -z "$file" ]]; then
echo "Verwendung: replace_variable \"variablenname\" \"neuer_wert\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
awk -v var_name="$var_name" -v new_value="$new_value" '
BEGIN {
replaced = 0
}
{
if ($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^[:alnum:]#])") {
# Ersetze gesamte Zeile durch normierte Form
print var_name " = " new_value
replaced = 1
} else {
print
}
}
END {
if (!replaced) {
print var_name " = " new_value > "/dev/stderr"
exit 3
}
}
' "$file" 1> "$tmp_file" 2> _missing_var.tmp
result=$?
if [[ $result -eq 3 ]]; then
# Variable nicht gefunden → neue hinzufügen
echo "" >> "$file"
cat _missing_var.tmp >> "$file"
echo " Variable '$var_name' wurde neu ans Ende angehängt."
rm -f "$tmp_file" _missing_var.tmp
return 0
fi
mv "$tmp_file" "$file"
rm -f _missing_var.tmp
echo "Variable '$var_name' wurde ersetzt."
return 0
}
replace_or_append_variable() {
local var_name="$1"
local new_value="$2"
local file="$3"
if [[ -z "$var_name" || -z "$new_value" || -z "$file" ]]; then
echo "Verwendung: replace_variable \"variablenname\" \"neuer_wert\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
awk -v var_name="$var_name" -v new_value="$new_value" '
BEGIN { replaced = 0 }
{
if ($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^[:alnum:]#])") {
print var_name " = " new_value
replaced = 1
} else {
print
}
}
END {
if (!replaced) {
printf("\n%s = %s\n", var_name, new_value) >> "/dev/stderr"
exit 3
}
}
' "$file" > "$tmp_file" 2> _var_append.tmp
result=$?
if [[ $result -eq 3 ]]; then
cat _var_append.tmp >> "$tmp_file"
echo "Variable '$var_name' wurde neu ans Ende angehängt."
else
echo "Variable '$var_name' wurde ersetzt."
fi
mv "$tmp_file" "$file"
rm -f _var_append.tmp
return 0
}
delete_variable() {
local var_name="$1"
local file="$2"
if [[ -z "$var_name" || -z "$file" ]]; then
echo "Verwendung: delete_variable \"variablenname\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
awk -v var_name="$var_name" '
# match: key = val, key=val, key val
!($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^[:alnum:]#])") {
print
}
' "$file" > "$tmp_file"
mv "$tmp_file" "$file"
echo "Nur Variable '$var_name' wurde gelöscht (Kommentare erhalten)."
return 0
}
delete_code_block_with_comments() {
local block_name="$1"
local file="$2"
if [[ -z "$block_name" || -z "$file" ]]; then
echo "Verwendung: delete_block_with_comments \"blockname\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
awk -v block_name="$block_name" '
function count_char(str, c) {
n = 0
for (i = 1; i <= length(str); i++) {
if (substr(str, i, 1) == c) n++
}
return n
}
{
lines[NR] = $0
if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") {
# Rückwärts prüfen, ob vorherige Zeilen nur Kommentare oder leer sind
start = NR
for (i = NR - 1; i >= 1; i--) {
if (lines[i] ~ /^#|^\s*$/) {
start = i
} else {
break
}
}
in_block = 1
brace_depth = count_char($0, "{") - count_char($0, "}")
skip_until = NR
next
}
if (in_block) {
brace_depth += count_char($0, "{") - count_char($0, "}")
if (brace_depth <= 0) {
in_block = 0
for (i = start; i <= NR; i++) {
deleted[i] = 1
}
}
next
}
}
END {
for (i = 1; i <= NR; i++) {
if (!(i in deleted)) {
print lines[i]
}
}
}
' "$file" > "$tmp_file"
mv "$tmp_file" "$file"
echo "Block '$block_name' inkl. vorangehender Kommentare wurde gelöscht."
return 0
}
delete_variable_with_comments() {
local var_name="$1"
local file="$2"
if [[ -z "$var_name" || -z "$file" ]]; then
echo "Verwendung: delete_variable_with_comments \"variablenname\" \"/pfad/zur/datei\""
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Datei '$file' existiert nicht."
return 2
fi
local tmp_file
tmp_file=$(mktemp)
awk -v var_name="$var_name" '
{
lines[NR] = $0
if ($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^=[:alnum:]])") {
# Rückwärts: vorangehende Kommentarzeilen (ohne Leerzeile)
start = NR
for (i = NR - 1; i >= 1; i--) {
if (lines[i] ~ /^[[:space:]]*#/) {
start = i
} else if (lines[i] ~ /^[[:space:]]*$/) {
break
} else {
break
}
}
for (i = start; i <= NR; i++) {
delete lines[i]
}
}
}
END {
for (i = 1; i <= NR; i++) {
if (i in lines) {
print lines[i]
}
}
}
' "$file" > "$tmp_file"
mv "$tmp_file" "$file"
echo "Variable '$var_name' inkl. zugehöriger Kommentare wurde gelöscht."
return 0
}
EOF
echo "_version=\"${_version}\" # dovecot version" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "dovecot_main_version=${dovecot_main_version}" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "dovecot_major_version=${dovecot_major_version}" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "dovecot_minor_version=${dovecot_minor_version}" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "dovecot_patch_level=${dovecot_patch_level}" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "dovecot_minor_patch_level=${dovecot_minor_patch_level}" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "_pigeonhole=\"${_pigeonhole}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "postmaster_address=\"${postmaster_address}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "systemd_support=${systemd_support}" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "_src_base_dir=\"${_src_base_dir}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "postfix_main_cf=\"${postfix_main_cf}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "hostname=\"${hostname}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "ipv4=\"${ipv4}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "ipv6"=\"${ipv6}\" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "imap_listener_adresses=\"${imap_listener_adresses}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "imaps_listener_adresses=\"${imaps_listener_adresses}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "pop_listener_adresses=\"${pop_listener_adresses}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "pops_listener_adresses=\"${pops_listener_adresses}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "xmpp_listener=${xmpp_listener}" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
if $xmpp_listener ; then
echo "xmpp_listener_addresses=\"${xmpp_listener_addresses}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "xmpp_listener_port=\"${xmpp_listener_port}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
fi
echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "database=\"${database}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "dbhost=\"${dbhost}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "dbname=\"${dbuser}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "dbuser=\"${dbuser}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "dbpassword=\"${dbpassword}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "PGPASSWORD=\"${dbpassword}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "MYSQL_CREDENTIALS=\"${DEFAULT_MYSQL_CREDENTIALS}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "default_pass_scheme=\"${default_pass_scheme}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "cert_base_dir=\"${cert_base_dir}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "server_cert=\"${server_cert}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "server_key=\"${server_key}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
if [[ $dovecot_major_version -ge 3 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -ge 3 ]] ); then
echo "dh_pem_file=\"${dh_pem_file}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
fi
echo "ssl_cipher_list=\"${ssl_cipher_list}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "imap_cert=\"${imap_cert}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "imap_key=\"${imap_key}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "pop_cert=\"${pop_cert}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "pop_key=\"${pop_key}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "spam_folder=\"${spam_folder}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "max_userip_connections"=${max_userip_connections} >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
echo "plugin_expire=${plugin_expire}" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
#echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
if ! $update ;then
if [[ "$database" = "psql" ]] || [[ "$database" = "postgres" ]]; then
warn "Take care, your PostgreSQL configuration (pg_hba.conf) contains the following line:\n\n\t pg_hba.conf:\n\t \033[1mlocal all postfix trust\033[m"
fi
fi
echononl "Sind die Angaben richtig [ja/nein]: "
read OK
while [ "X$OK" != "Xyes" -a "X$OK" != "XYes" -a "X$OK" != "Xja" -a "X$OK" != "XJa" \
-a "X$OK" != "XNo" -a "X$OK" != "Xno" -a "X$OK" != "Xn" -a "X$OK" != "Xnein" -a "X$OK" != "XNein" ]
do
echononl "falsche Angabe! [ja/nein] :"
read OK
done
[ $OK = "Yes" -o $OK = "yes" -o "$OK" = "ja" -o "$OK" = "Ja" ] || fatal "Edit '$(basename $conf_file)' and correct variables"
## - Let make use multiple cores (-j<number of cores +1>)
## -
export MAKEFLAGS=-j$(expr `grep "^processor" /proc/cpuinfo | sort -u | wc -l` - 1)
# -------------
# - Begin Install/Update
# -------------
echo ""
if $update ;then
_new=false;
else
_new=true;
fi
if [ "$database" = "mysql" ]; then
db_driver=mysql
else
db_driver=pgsql
fi
if $_new ; then
if [ "$database" = "mysql" ]; then
echo ""
echo "--"
echo ""
echo "Gib MySQL credentials für den root user an.."
echo ""
echo "Possible values could be:"
echo " -u root -p<Passwort>"
echo " -u root -S /run/mysqld/mysqld.sock"
echo " --login-path=local"
echo " --defaults-file=/usr/local/mysql/sys-maint.cnf"
echo " --defaults-file=/etc/mysql/debian.cnf"
echo " ..."
echo ""
echo -e " Type \"\033[33mNone\033[m\" if no credentials are needed for root user (MariaDB)"
echo ""
MYSQL_CREDENTIALS=""
if [[ -n "${DEFAULT_MYSQL_CREDENTIALS}" ]] ; then
while [[ -z "${MYSQL_CREDENTIALS}" ]] ; do
echononl "MySQL credentials [${DEFAULT_MYSQL_CREDENTIALS}]: "
read MYSQL_CREDENTIALS
if [[ -z "${MYSQL_CREDENTIALS}" ]] ;then
MYSQL_CREDENTIALS="${DEFAULT_MYSQL_CREDENTIALS}"
fi
done
else
while [[ -z "${MYSQL_CREDENTIALS}" ]] ; do
echononl "MySQL credentials: "
read MYSQL_CREDENTIALS
if "${MYSQL_CREDENTIALS}" ]] ; then
echo -e "\n\t\033[33m\033[1mMySQL credentials are required (or type\033[33mNone\033[m) : "
continue
fi
if [[ "$(trim ${MYSQL_CREDENTIALS,,})" = 'none' ]] ; then
MYSQL_CREDENTIALS=""
break
fi
done
fi
echo ""
echo "--"
echo ""
echo ""
if [[ "${MYSQL_CREDENTIALS}" != "${DEFAULT_MYSQL_CREDENTIALS}" ]] ; then
echo "MYSQL_CREDENTIALS=\"${MYSQL_CREDENTIALS}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE}
fi
fi
fi
export PGPASSWORD=$dbpassword
echo -e "\033[1mDoing some backups\033[m.."
echononl " Backup existing installation log directory.."
if [[ -d "${_log_dir}" ]]; then
mv "${_log_dir}" "${_log_dir}.${backup_date}"
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Cannot Backup (move) directory '${_log_dir}'"
fi
else
echo -e "$rc_skipped"
fi
echononl " Backup existing installation directory.."
if [[ -d "/usr/local/dovecot-${_version}" ]]; then
mv "/usr/local/dovecot-${_version}" "/usr/local/dovecot-${_version}.${backup_date}"
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Cannot Backup (move) directory '${_log_dir}'"
echononl "Proceed instllation [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
else
echo -e "$rc_skipped"
fi
echononl " Backup existing source directory.."
if [[ -d "${_src_base_dir}/dovecot-${_version}" ]]; then
mv "${_src_base_dir}/dovecot-${_version}" "${_src_base_dir}/dovecot-${_version}.${backup_date}"
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Cannot Backup (move) directory '${_src_base_dir}/dovecot-${_version}'"
echononl "Proceed instllation [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
else
echo -e "$rc_skipped"
fi
mkdir -p $_log_dir
## -----------------
## --- Download
cd ${_src_base_dir}
echo ""
echo -e "\033[1mDownload sources\033[m.."
## - Downloud Dovecot 2.2.x
## -
echononl " Download dovecot-${_version}.tar.gz"
if [ ! -f "${_src_base_dir}/dovecot-${_version}.tar.gz" ]; then
wget --no-check-certificate https://dovecot.org/releases/${dovecot_main_version}/dovecot-${_version}.tar.gz > /dev/null 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Direct download of 'dovecot-${_version}.tar.gz' failed
Download \033[1mdovecot-${_version}.tar.gz\033[m manually and proceed instllation."
echononl "Proceed instllation [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
else
echo -e "$rc_skipped"
fi
## - Download Pigeonhole for Dovecot v2.2
## -
if [[ ${dovecot_major_version} -eq 2 ]] && [[ ${dovecot_minor_version} -lt 4 ]] ; then
echononl " Download dovecot-${dovecot_main_version}-pigeonhole-${_pigeonhole}.tar.gz.."
if [ ! -f "${_src_base_dir}/dovecot-${dovecot_main_version}-pigeonhole-${_pigeonhole}.tar.gz" ]; then
wget --no-check-certificate https://pigeonhole.dovecot.org/releases/${dovecot_main_version}/dovecot-${dovecot_main_version}-pigeonhole-${_pigeonhole}.tar.gz > /dev/null 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Direct download of 'dovecot-${dovecot_main_version}-pigeonhole-${_pigeonhole}.tar.gz' failed
Download \033[1mdovecot-${dovecot_main_version}-pigeonhole-${_pigeonhole}.tar.gz\033[m manually
and proceed instllation."
echononl " Proceed instllation [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
else
echo -e "$rc_skipped"
fi
dovecot_pigeonhole_archiv="dovecot-${dovecot_main_version}-pigeonhole-${_pigeonhole}.tar.gz"
else
echononl " Download dovecot-pigeonhole-${_pigeonhole}.tar.gz.."
if [ ! -f "${_src_base_dir}/dovecot-pigeonhole-${_pigeonhole}.tar.gz" ]; then
wget --no-check-certificate https://pigeonhole.dovecot.org/releases/${dovecot_main_version}/dovecot-pigeonhole-${_pigeonhole}.tar.gz > /dev/null 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
dovecot_pigeonhole_archiv="dovecot-pigeonhole-${_pigeonhole}.tar.gz"
else
echo -e "$rc_failed"
error "Direct download of 'Pigeonhole Sieve and ManageSieve' source archiv failed
Download Pigeonhole Sieve and ManageSieve manually and name it to
\033[1mdovecot-pigeonhole-${_pigeonhole}.tar.gz\033[m\n"
echononl " Proceed instllation [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
else
echo -e "$rc_skipped"
fi
dovecot_pigeonhole_archiv="dovecot-pigeonhole-${_pigeonhole}.tar.gz"
fi
dovecot_pigeonhole_archiv_prefix="${dovecot_pigeonhole_archiv%.tar.gz}"
dovecot_pigeonhole_archiv_dir="${dovecot_pigeonhole_archiv%.tar.gz}"
if $_new ; then
## - Install reqired debian packages
## -
echo ""
echo -e "\033[1mInstalling required debian packages\033[m.."
echononl " Installing libpq5 libpq-dev .."
if ! dpkg -l libpq-dev | grep -e "^ii" | grep libpq-dev > /dev/null ; then
apt-get install libpq5 libpq-dev > ${_log_dir}/debian-install.log 2&>1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "installing debian package(s) failed"
fi
else
echo -e "$rc_skipped"
fi
echononl " Installing libkrb5-dev .."
if ! dpkg -l libkrb5-dev | grep -e "^ii" | grep libkrb5-dev > /dev/null ; then
apt-get install libkrb5-dev >> ${_log_dir}/debian-install.log 2&>1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "installing debian package(s) failed"
fi
else
echo -e "$rc_skipped"
fi
fi
## -----------------
## - Create Users/groups needed for dovecot
echo ""
echo -e "\033[1mCreate required users/groups\033[m.."
echononl " Create group dovecot.."
if ! grep dovecot /etc/group > /dev/null ; then
addgroup --system --gid 91 dovecot > ${_log_dir}/system.log 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Create group failed
fi
else
echo -e "$rc_skipped"
fi
echononl " Create user dovecot.."
if ! grep dovecot /etc/passwd > /dev/null ; then
adduser --system --home /var/empty --no-create-home --shell /usr/sbin/nologin \
--ingroup dovecot --uid 91 dovecot > ${_log_dir}/system.log 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Create user failed
fi
else
echo -e "$rc_skipped"
fi
echononl " Add Apache User (${http_user}) to group 'dovecot'.."
if getent group dovecot 2> /dev/null | grep -q "\b${http_user}\b" > /dev/null 2>&1 ; then
echo -e "$rc_skipped"
else
usermod -a -G dovecot $http_user > ${_log_dir}/system.log 2>&1
if [[ $? -eq 0 ]] ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Failed to add Apache User (${http_user}) to group 'dovecot'!"
fi
fi
echononl " Create group dovenull.."
if ! grep dovenull /etc/group > /dev/null ; then
addgroup --system --gid 65533 dovenull > ${_log_dir}/system.log 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Create group failed
fi
else
echo -e "$rc_skipped"
fi
echononl " Create user dovenull.."
if ! grep dovenull /etc/passwd > /dev/null ; then
adduser --system --home /var/empty --no-create-home --shell /usr/sbin/nologin \
--ingroup dovenull --uid 65533 dovenull > ${_log_dir}/system.log 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Create user failed
fi
else
echo -e "$rc_skipped"
fi
if $update ; then
# - Deaktiviere Cronjobs
# -
echo ""
echononl " Backup Crontab (user toot) to '$_backup_crontab_file'"
crontab -l > $_backup_crontab_file 2> $log_file
if [[ $? -eq 0 ]]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Backup Crontab to '$_backup_crontab_file' failed"
# If no crontab was present, the backup file contains
# th string "no crontab fo root". Better to delete the
# backup crontab file..
#
rm -f $_backup_crontab_file
fi
echononl " Remove crontab for user root.."
crontab -r > $log_file 2>&1
if [[ $? -eq 0 ]]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error ""
fi
fi
## -----------------
## --- Install Base System
echo ""
echo -e "\033[1mInstalling Base System\033[m.."
## - Unpack dovecot sources
## -
cd ${_src_base_dir}
echononl " Unpack dovecot-${_version}.tar.gz.."
tar -xzf dovecot-${_version}.tar.gz > /dev/null
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Extracting dovecot failed
fi
cd dovecot-${_version}
## - Configure dovecot
## -
config_params="
--prefix=/usr/local/dovecot-${_version} \
--with-${db_driver} \
--with-gssapi=yes
--with-ldap=yes
--with-rundir=/run/dovecot"
if $systemd_support ; then
config_params="$config_params \
--with-systemd"
fi
#--with-systemdsystemunitdir=/etc/systemd/system/"
echononl " Configure Dovecot.."
#./configure \
# --prefix=/usr/local/dovecot-${_version} \
# --with-${db_driver} \
# --with-gssapi=yes > ${_log_dir}/dovecot-${_version}-configure.log 2>&1
#--with-systemdsystemunitdir=/etc/systemd/system \
LDFLAGS="-s" \
./configure $config_params > ${_log_dir}/dovecot-${_version}-configure.log 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Configuring dovecot failed
fi
## - Compile dovecot
## -
echononl " Compile Dovecot Sources.."
make > ${_log_dir}/dovecot-${_version}-make.log 2>&1 || clean_up 1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Compiling dovecot failed
fi
## -----------------
## --- Stop dovecot if running
echononl " Stop dovecot service.."
if ps ax 2> /dev/null | grep -q -E "/usr/local/dovecot[0-9.-]*/sbin/dovecot" > /dev/null 2>&1 ; then
if $systemd_support ; then
systemctl stop dovecot > /dev/null 2>&1
else
/etc/init.d/dovecot stop > /dev/null 2>&1
fi
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Stopping dovecot service failed"
fi
else
echo -e "$rc_skipped"
fi
blank_line
echononl " Remove dovecot service file if exists.."
if [[ -f "/etc/systemd/system/dovecot.service" ]] ; then
rm -f "/etc/systemd/system/dovecot.service" > /dev/null 2>&1
if [[ "$?" -gt 0 ]]; then
echo -e "$rc_failed"
error "Removing file '/etc/systemd/system/dovecot.service' failed."
else
echo -e "$rc_done"
fi
else
echo -e "$rc_skipped"
fi
echononl " Remove dovecot systemd's socket file if exists.."
if [[ -f "/etc/systemd/system/dovecot.socket" ]] ; then
rm -f "/etc/systemd/system/dovecot.socket" > /dev/null 2>&1
if [[ "$?" -gt 0 ]]; then
echo -e "$rc_failed"
error "Removing systemd's socket file '/etc/systemd/system/dovecot.socket' failed."
else
echo -e "$rc_done"
fi
else
echo -e "$rc_skipped"
fi
echononl " Remove directory '/etc/systemd/system/dovecot.service.d' if exists.."
if [[ -d "/etc/systemd/system/dovecot.service.d" ]] ; then
rm -rf "/etc/systemd/system/dovecot.service.d" > /dev/null 2>&1
if [[ "$?" -gt 0 ]]; then
echo -e "$rc_failed"
error "Removing directory '/etc/systemd/system/dovecot.service.d' failed."
else
echo -e "$rc_done"
fi
else
echo -e "$rc_skipped"
fi
blank_line
## - Install dovecot
## -
echononl " Install Dovecot into Folder /usr/local/dovecot-${_version}"
make install > ${_log_dir}/dovecot-${_version}-install.log 2>&1 || clean_up 1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Installing dovecot failed
fi
blank_line
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Create Configuration Directory 'etc/dovecot/conf.d'.."
if [[ ! -d "/usr/local/dovecot-${_version}/etc/dovecot/conf.d" ]] ; then
mkdir -p "/usr/local/dovecot-${_version}/etc/dovecot/conf.d" > $log_file 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "$(cat $log_file)"
echononl " continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
_failed=false
touch "${_conf_file}" > ${log_file}
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating empty file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
touch "${_conf_file}" > ${log_file}
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating empty file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## Mail Location ans Namespace Settigs
##
EOF
if [[ $? -gt 0 ]] ; then
_failed=true
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
_failed=false
touch "${_conf_file}" > ${log_file}
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating empty file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## SSL settings
##
EOF
if [[ $? -gt 0 ]] ; then
_failed=true
fi
blank_line
fi
## - Add /usr/local/dovecot/bin to PATH variable
## -
## - Edit /etc/profile and add bevor "export PATH" directive:
## -
## - checkdir="/usr/local/dovecot/bin"
## - if [ -d $checkdir ]; then
## - PATH=$PATH:$checkdir
## - fi
## -
echononl " Add /usr/local/dovecot/bin to PATH variable.."
if ! grep "checkdir=\"/usr/local/dovecot/bin\"" /etc/profile > /dev/null ; then
perl -i -n -p -e "s#^(\s*)(export\ +PATH)#checkdir=\"/usr/local/dovecot/bin\"\nif [ -d \\\$checkdir ]; then\n PATH=\\\$PATH:\\\$checkdir\nfi\n\n\1\2#" /etc/profile
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Adjusting /etc/profile failed
fi
else
echo -e "$rc_skipped"
fi
echononl " Copy Manpages if not exists.."
## - Manpages
## -
if ! grep /usr/local/dovecot/share/man /etc/manpath.config > /dev/null 2<&1 ; then
echo >> /etc/manpath.config
echo "MANDATORY_MANPATH /usr/local/dovecot/share/man /var/cache/man" >> /etc/manpath.config
echo "MANPATH_MAP /usr/local/dovecot/bin /usr/local/dovecot/share/man" >> /etc/manpath.config
echo "MANDB_MAP /usr/local/dovecot/share/man /var/cache/man" >> /etc/manpath.config
echo -e "$rc_done"
else
echo -e "$rc_skipped"
fi
## -----------------
## --- Install Pigeonhole ManageSieve
cd ${_src_base_dir}
echo ""
echononl " Extracting ${dovecot_pigeonhole_archiv}.."
gunzip < ${_src_base_dir}/${dovecot_pigeonhole_archiv} | tar -C ${_src_base_dir} -xf -
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Extracting '${dovecot_pigeonhole_archiv}' failed
fi
cd ${dovecot_pigeonhole_archiv_dir}
echononl " Configure Pigeonhole ManageSieve.."
./configure \
--prefix=/usr/local/dovecot-${_version} \
--with-dovecot=/usr/local/dovecot-${_version}/lib/dovecot > ${_log_dir}/${dovecot_pigeonhole_archiv_prefix}-configure.log 2<&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Configuring Pigeonhole ManageSieve failed
fi
echononl " Compile Pigeonhole ManageSieve.."
make > ${_log_dir}/${dovecot_pigeonhole_archiv_prefix}-make.log 2<&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Compiling Pigeonhole ManageSieve failed
fi
echononl " Install Pigeonhole ManageSieve.."
make install > ${_log_dir}/${dovecot_pigeonhole_archiv_prefix}-install.log 2<&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Installing Pigeonhole ManageSieve failed
fi
## -----------------
## --- Configure dovecot services
#echo ""
#echo -e "\033[1mConfigure Dovecot\033[m.."
blank_line
## - Copy example config files to the config directory
## -
echononl " Copy example config files to the config directory.."
if [[ ${dovecot_major_version} -eq 2 ]] && [[ ${dovecot_minor_version} -lt 4 ]] ; then
cp -r /usr/local/dovecot-${_version}/share/doc/dovecot/example-config/* \
/usr/local/dovecot-${_version}/etc/dovecot/ > /dev/null 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error Compiling Pigeonhole ManageSieve failed
fi
else
echo -e "$rc_skipped"
fi
echononl " Backup main configuration file 'dovecot.conf'.."
if [[ -f "/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf" ]] ; then
cp -a /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf \
/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf.ORIG > /dev/null 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error Compiling Pigeonhole ManageSieve failed
fi
else
echo -e "$rc_skipped"
fi
blank_line
#echo -e "\033[1mBase install of Dovecot and Pigeonhole ManageSieve finished\033[m.."
#
#blank_line
#
#echononl "Proceed instllation [yes/no]: "
#read OK
#OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
#while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
# echononl "Wrong entry! - repeat [yes/no]: "
# read OK
#done
#[[ $OK = "yes" ]] || fatal "Abbruch durch User"
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
# - edit /usr/local/dovecot/etc/dovecot/dovecot.conf
# -
# - protocols {
# - imap = yes
# - lmtp = yes
# - pop3 = yes
# - sieve = yes
# - }
# -
# - base_dir = /run/dovecot
# - state_dir = /run/dovecot
# -
# - listen = $ipv4 $ipv6
# -
# - mail_home = /var/vmail/%{user | domain}/%{user | username}
# - mail_path = ~/Maildir
# - mail_driver = Maildir
# -
# - shutdown_clients = no
# -
# - ssl_server {
# - ssl = yes
# - cert_file = /etc/dovecot/ssl/mailserver.crt
# - key_file = /etc/dovecot/ssl/mailserver.key
# - }
# -
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf"
echononl " Delete block 'namespace inbox' in file '$(basename "${_conf_file}")'.."
if grep -qE '^\s*namespace\s+inbox\s*{' "${_conf_file}"; then
delete_code_block "namespace inbox" "${_conf_file}"
if [[ $? -gt 1 ]] ; then
echo -e "$rc_failed"
error "Deleting block 'namespace inbox' in file '$(basename "${_conf_file}")' failed!"
else
echo -e "$rc_done"
fi
else
echo -e "$rc_skipped"
fi
_protocols_block="protocols {\n imap = yes\n lmtp = yes\n pop3 = yes\n sieve = yes\n}"
if [[ -n "$ipv6" ]]; then
_listen="$ipv4 $ipv6"
else
_listen="$ipv4"
fi
_base_dir="/run/dovecot"
_state_dir="/run/dovecot"
_mail_home="/var/vmail/%{user | domain}/%{user | username}"
_mail_driver="Maildir"
_mail_path="~/Maildir"
_shutdown_clients="no"
_cert_file="/etc/dovecot/ssl/mailserver.crt"
_key_file="/etc/dovecot/ssl/mailserver.key"
_ssl_server_block="ssl_server {\n ssl = yes\n cert_file = ${_cert_file}\n key_file = ${_key_file}\n}"
echononl " Adjust file $(basename "${_conf_file}").."
# # Delete all lines that begin with !include and also delete the following line
# # if it is empty or contains only whitespace.
# #
# sed -i '/^!include/ {
# N
# /^\(!include.*\n[[:space:]]*\)$/d
# /^!include.*/d
# }' "${_conf_file}" || _failed=true
# Delete all lines beginning with !include, together with all comment lines
# directly preceding it (#...) - even several in a row, and also the line
# following it if it is empty or only contains whitespace.
#
awk '
{
zeile[NR] = $0
typ[NR] = "keep"
if ($0 ~ /^[[:space:]]*#/) typ[NR] = "comment"
if ($0 ~ /^[[:space:]]*$/) typ[NR] = "empty"
if ($0 ~ /^[[:space:]]*!include/) typ[NR] = "include"
}
END {
for (i = 1; i <= NR; i++) {
if (typ[i] == "include") {
# Vorherige Kommentarzeilen löschen
j = i - 1
while (j > 0 && typ[j] == "comment") {
typ[j] = "delete"
j--
}
# Include-Zeile löschen
typ[i] = "delete"
# Nachfolgende Leerzeile löschen (falls vorhanden)
if (typ[i+1] == "empty") {
typ[i+1] = "delete"
}
}
}
for (i = 1; i <= NR; i++) {
if (typ[i] != "delete") print zeile[i]
}
}
' "${_conf_file}" > "${_conf_file}.tmp" && mv "${_conf_file}.tmp" "${_conf_file}"
if grep -qE '^\s*protocols\s*{' "${_conf_file}"; then
sed -i "/^\s*protocols\s*{/,/^}/c\
${_protocols_block}" ${_conf_file} || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Enable wanted protocols:
$(echo -e "${_protocols_block}")
EOF
#echo -e "\n${_protocols_block}" >> "${_conf_file}" || _failed=true
fi
if grep -qE '^\s*listen\s*=' "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(listen\ ?=.*)#listen = ${_listen}#g" \
"${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Enable wanted protocols:
listen = ${_listen}
EOF
#echo -e "\nlisten = ${_listen}" >> "${_conf_file}" || _failed=true
fi
if grep -qE '^\s*base_dir\s*=' "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(base_dir\ ?=.*)#base_dir = ${_base_dir}#g" \
"${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Base directory where to store runtime data.
base_dir = ${_base_dir}
EOF
#echo -e "\nbase_dir = ${_base_dir}" >> "${_conf_file}" || _failed=true
fi
if grep -qE '^\s*state_dir\s*=' "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(state_dir\ ?=.*)#state_dir = ${_state_dir}#g" \
"${_conf_file}" || _failed=true
else
echo -e "\nstate_dir = ${_state_dir}" >> "${_conf_file}" || _failed=true
fi
if grep -qE '^\s*mail_home\s*=' "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(mail_home\ ?=.*)#mail_home = ${_mail_home}#g" \
"${_conf_file}" || _failed=true
else
echo -e "\nmail_home = ${_mail_home}" >> "${_conf_file}" || _failed=true
fi
if grep -qE '^\s*mail_path\s*=' "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(mail_path\ ?=.*)#mail_path = ${_mail_path}#g" \
"${_conf_file}" || _failed=true
else
echo -e "\nmail_path = ${_mail_driver}" >> "${_conf_file}" || _failed=true
fi
if grep -qE '^\s*mail_driver\s*=' "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(mail_driver\ ?=.*)#mail_driver = ${_mail_driver}#g" \
"${_conf_file}" || _failed=true
else
echo -e "\nmail_driver = ${_mail_driver}" >> "${_conf_file}" || _failed=true
fi
if grep -qE '^\s*shutdown_clients\s*=' "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(shutdown_clients\ ?=.*)#shutdown_clients = ${_shutdown_clients}#g" \
"${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Should all processes be killed when Dovecot master process shuts down.
# Setting this to "no" means that Dovecot can be upgraded without
# forcing existing client connections to close (although that could also be
# a problem if the upgrade is e.g. because of a security fix).
shutdown_clients = ${_shutdown_clients}
EOF
#echo -e "\nshutdown_clients = ${_shutdown_clients}" >> "${_conf_file}" || _failed=true
fi
if grep -qE '^\s*ssl_server\s*{' "${_conf_file}"; then
sed -i "/^\s*ssl_server\s*{/,/^}/c\
${_ssl_server_block}" ${_conf_file} || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# SSL/TLS Configuration
$(echo -e "${_ssl_server_block}")
EOF
fi
cat <<EOF >> "${_conf_file}" || _failed=true
# Most of the actual configuration gets included below. The filenames are
# first sorted by their ASCII value and parsed in that order. The 00-prefixes
# in filenames are intended to make it easier to understand the ordering.
!include_try conf.d/*.conf
# A config file can also tried to be included without giving an error if
# it's not found:
!include_try local.conf
EOF
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Adjusting Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf failed"
echo ""
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Interupted by user"
fi
else
## - edit /usr/local/dovecot/etc/dovecot/dovecot.conf
## -
## - protocols = imap pop3 sieve
## - listen = $ipv4 $ipv6
## - base_dir =/run/dovecot/
## - state_dir = /run/dovecot
## - shutdown_clients = no
## -
## - dict {
## - expire = $db_driver:/usr/local/dovecot/etc/dovecot/sql-dict.conf.ext
## - }
## -
echononl " Adjust file dovecot.conf.."
if [[ -n "$ipv6" ]]; then
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(listen\ ?=.*)#\1\#\# \2\n\1listen = $ipv4 $ipv6#g" \
/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true
else
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(listen\ ?=.*)#\1\#\# \2\n\1listen = $ipv4#g" \
/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true
fi
perl -i -n -p -e "s#^([ ]*)\#?\ ?(protocols\ ?=.*)#\1\#\# \2\n\1protocols = imap pop3 sieve#g" \
/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(base_dir\ ?=.*)#\1\#\# \2\n\1base_dir = /run/dovecot/\n\nstate_dir = /run/dovecot#g" \
/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(shutdown_clients\ ?=.*)#\1\#\# \2\n\1shutdown_clients = no#g" \
/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true
if $plugin_expire ; then
perl -i -n -p \
-e "s#^([ ]*)(dict\ +{.*)#\1\2\n\1 expire = $db_driver:/usr/local/dovecot/etc/dovecot/sql-dict.conf.ext#g" \
/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true
fi
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf failed"
fi
fi
blank_line
#echononl "Proceed instllation [yes/no]: "
#read OK
#OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
#while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
# echononl "Wrong entry! - repeat [yes/no]: "
# read OK
#done
#[[ $OK = "yes" ]] || fatal "Abbruch durch User"
if $_new ; then
if [ "$db_driver" = "pgsql" ]; then
echononl " Check if database '$dbname' already exists.."
count=`su - postgres -c "psql -q -A -t -l" 2> ${_log_dir}/error.log | grep -c -e "^$dbname"`
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Checking existence of database '$dbname' failed!"
echononl " continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
if [ $count -eq 0 ];then
echononl " Create database user ${dbuser}.."
echo "CREATE ROLE $dbuser WITH LOGIN NOCREATEDB NOCREATEROLE NOSUPERUSER ENCRYPTED PASSWORD '$dbpassword'" \
| su - postgres -c "psql" > /dev/null 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Creating database user $dbuser failed
fi
echononl " Create database ${dbname}.."
su - postgres -c "createdb -E utf8 -O ${dbuser} $dbname"
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal Creating database $dbname failed
fi
fi
## - Create table expires in database ${dbname}
## -
echononl " Create table expires in database ${dbname}.."
if $plugin_expire ; then
cat << EOF | psql -U$dbuser $dbname > ${_log_dir}/error.log 2>&1
CREATE TABLE IF NOT EXISTS expires (
username varchar(100) not null,
mailbox varchar(255) not null,
expire_stamp integer not null,
primary key (username, mailbox)
);
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "$(cat ${_log_dir}/error.log)"
echononl " continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
else
echo -e "$rc_skipped"
fi
echononl " Create function merge_expires() / trigger mergeexpires.."
if $plugin_expire ; then
cat << EOF | psql -U$dbuser $dbname > /dev/null 2>&1
CREATE LANGUAGE plpgsql;
create or replace function merge_expires() returns trigger as \$\$
begin
update expires set expire_stamp = new.expire_stamp
where username = new.username and mailbox = new.mailbox;
if found then
return null;
else
return new;
end if;
end;
\$\$ language plpgsql;
create trigger mergeexpires before insert on expires
for each row execute procedure merge_expires();
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "$(cat ${_log_dir}/error.log)"
echononl " continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
else
echo -e "$rc_skipped"
fi
elif [ "$db_driver" = "mysql" ]; then
if ! mysql ${MYSQL_CREDENTIALS} -N -s -e \
"SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$dbname'" 2>/dev/null \
| grep $_db_name > /dev/null 2>&1 ; then
echononl " Create database ${dbname}.."
mysql ${MYSQL_CREDENTIALS} -N -s -e \
"CREATE DATABASE IF NOT EXISTS $dbname CHARACTER SET utf8 COLLATE utf8_general_ci" > ${_log_dir}/error.log 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "$(cat ${_log_dir}/error.log)"
echononl " continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
echononl " Create database user ${dbuser}.."
mysql ${MYSQL_CREDENTIALS} -N -s -e \
"GRANT ALL ON ${dbname}.* TO '${dbuser}'@'localhost' IDENTIFIED BY '$dbpassword'" > ${_log_dir}/error.log 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "$(cat ${_log_dir}/error.log)"
echononl " continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
echononl " Flushing database privileges.."
mysql ${MYSQL_CREDENTIALS} -N -s -e "FLUSH PRIVILEGES" > ${_log_dir}/error.log 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "$(cat ${_log_dir}/error.log)"
echononl " continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
fi
## - Create table expires in database ${dbname}
## -
echononl " Create table expires in database ${dbname}.."
if $plugin_expire ; then
cat << EOF | mysql -u$dbuser -p$dbpassword $dbname > /dev/null 2>&1
CREATE TABLE IF NOT EXISTS expires (
username varchar(100) not null,
mailbox varchar(255) not null,
expire_stamp integer not null,
primary key (username, mailbox)
);
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating table expires failed"
fi
else
echo -e "$rc_skipped"
fi
fi
fi
## - create sql-dict.conf.ext file
## -
echononl " Create file sql-dict.conf.ext with plugin 'expire'.."
if $plugin_expire ; then
if [ "$db_driver" = "pgsql" ]; then
cat <<EOF >/usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
connect = host=$dbhost user=$dbuser password=$dbpassword dbname=$dbname
# CREATE TABLE expires (
# username varchar(100) not null,
# mailbox varchar(255) not null,
# expire_stamp integer not null,
# primary key (username, mailbox)
# );
## - if using postgres, you need also to create a trigger as follows:
## -
## - first create language plpgsql if not yet created:
## -
# CREATE LANGUAGE plpgsql;
#
# CREATE OR REPLACE FUNCTION merge_expires() RETURNS TRIGGER AS \$\$
# BEGIN
# UPDATE expires SET expire_stamp = NEW.expire_stamp
# WHERE username = NEW.username AND mailbox = NEW.mailbox;
# IF FOUND THEN
# RETURN NULL;
# ELSE
# RETURN NEW;
# END IF;
# END;
# \$\$ LANGUAGE plpgsql;
#
# CREATE TRIGGER mergeexpires BEFORE INSERT ON expires
# FOR EACH ROW EXECUTE PROCEDURE merge_expires();
map {
pattern = shared/expire/\$user/\$mailbox
table = expires
value_field = expire_stamp
fields {
username = \$user
mailbox = \$mailbox
}
}
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Creating file sql-dict.conf.ext failed"
fi
elif [ "$db_driver" = "mysql" ]; then
## - create sql-dict.conf.ext file
## -
echononl " Create file sql-dict.conf.ext"
cat <<EOF >/usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
# CREATE TABLE expires (
# username varchar(100) not null,
# mailbox varchar(255) not null,
# expire_stamp integer not null,
# primary key (username, mailbox)
# );
map {
pattern = shared/expire/\$user/\$mailbox
table = expires
value_field = expire_stamp
fields {
username = \$user
mailbox = \$mailbox
}
}
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Creating file sql-dict.conf.ext failed"
fi
fi
else
echo -e "$rc_skipped"
fi
# edit /usr/local/dovecot/etc/dovecot/conf.d/10-master.conf
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf"
# edit /usr/local/dovecot/etc/dovecot/conf.d/10-master.conf
#
# default_process_limit = 1024
# default_client_limit = 10240
#
# default_vsz_limit = 512M
#
# !! Bemerkung !!
#
# Das Hochsetzen des default_client_limit Parameters auf einen Wert größer
# als 1024 geht nur dann wenn auch die Anzahl der zulässigen "open files"
# (default = 1024) geändert wird.
#
#
# Systemd System:
# ===============
#
# In der service datei (z.Bsp. /etc/systemd/system/multi-user.target.wants/dovecot.service)
# den Wert 'LimitNOFILE' hochsetzen:
#
# LimitNOFILE=32768 (must be greater or equal of 'default_client_limit')
#
# systemctl daemon-reload
# systemctl restart dovecot.service
#
# Im Falle von LX containern muss zusätzlich auf dem hostsystem
# in der datei '/etc/systemd/system.conf' der Wert für 'DefaultLimitNOFILE'
# hochgesetzt werden.
#
# System V systems:
# =================
# Das Hochsetzen des default_client_limit Parameters auf einen Wert größer
# als 1024 geht nur dann wenn auch die Anzahl der zulässigen "open files"
# (default = 1024) geändert wird. Z.Bsp. in der Datei /etc/init.d/dovecot
# durch Einfügen der zeile:
# ulimit -n 32768
#
# Linux VServer:
# put the following lines into /etc/security/limits.conf
#
# @staff hard nofile 32768
# root hard nofile 32768
#
# !! Mybe you have also create file /etc/vservers/*/ulimits/nofiles.hard
# with the same contents:
#
# @staff hard nofile 32768
# @adm hard nofile 32768
# root hard nofile 32768
#
# see also http://linux-vserver.org/Ulimit_Nofiles
#
#
# service imap-login {
# inet_listener imap {
# address = $imap_listener_adresses
# }
#
# inet_listener imaps {
# address = $imaps_listener_adresses
#
# }
#
# process_min_avail = 16
# }
#
# service pop3-login {
# inet_listener pop3 {
# address = $pop_listener_adresses
#
# }
# inet_listener pop3s {
# address = $pops_listener_adresses
#
# }
# }
#
# service submission-login {
#
# inet_listener submission {
# #port = 587
# }
#
# inet_listener submissions {
# #port = 465
# }
# }
#
# service lmtp {
#
# unix_listener /var/spool/postfix/private/dovecot-lmtp {
# user = postfix
# group = postfix
# mode = 0660
# }
#
# # Create inet listener only if you can't use the above UNIX socket
# #inet_listener lmtp {
# # Avoid making LMTP visible for the entire internet
# #address =
# #port =
# #}
# }
#
# service imap {
#
# # tell imap to do post-login lookup using a socket called "imap-postlogin"
# executable = imap post-login
#
# # Most of the memory goes to mmap()ing files. You may need to increase this
# # limit if you have huge mailboxes.
# #vsz_limit = $default_vsz_limit
#
# # Max. number of IMAP processes (connections)
# #process_limit = 1024
# }
#
# service pop3 {
#
# # tell imap to do post-login lookup using a socket called "imap-postlogin"
# executable = pop3 post-login
#
# # Max. number of POP3 processes (connections)
# #process_limit = 1024
# }
#
# service submission {
#
# # Max. number of SMTP Submission processes (connections)
# #process_limit = 1024
# }
#
# service auth {
#
# # Auth Listener (XMPP - Jabber)
# inet_listener {
# address = $xmpp_listener_addresses
# port = $xmpp_listener_port
# }
#
# unix_listener auth-userdb {
# mode = 0666
# user = dovecot
# group = dovecot
# }
#
# unix_listener /var/spool/postfix/private/dovecot-auth {
# mode = 0666
# user = postfix
# group = postfix
# }
#
# }
#
# service auth-worker {
# # Auth worker process is run as root by default, so that it can access
# # /etc/shadow. If this isn't necessary, the user should be changed to
# # $SET:default_internal_user.
# #user = root
# }
#
# service dict {
# # If dict proxy is used, mail processes should have access to its socket.
# # For example: mode=0660, group=vmail and global mail_access_groups=vmail
# unix_listener dict {
# #mode = 0600
# #user =
# #group =
# }
# }
#
echononl " Adjusting file $(basename "${_conf_file}").."
:> "${_conf_file}"
_param="default_process_limit"
_val=1024
if grep -qE "^\s*${_param}\s*=" "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \
"${_conf_file}" >> "${log_file}" 2>&1 || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Default value for parameter 'service_process_limit', if not overridden by service-specific configuration.
${_param} = ${_val}
EOF
fi
_param="default_client_limit"
_val=10240
if grep -qE "^\s*${_param}\s*=" "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \
"${_conf_file}" >> "${log_file}" 2>&1 || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Default value for service_client_limit, if not overridden by service-specific configuration.
${_param} = ${_val}
EOF
fi
_param="default_vsz_limit"
_val="512M"
if grep -qE "^\s*${_param}\s*=" "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \
"${_conf_file}" >> "${log_file}" 2>&1 || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Default value for service_vsz_limit, if not overridden by service-specific configuration.
${_param} = ${_val}
EOF
fi
read -r -d '' NEW_BLOCK <<EOF
service imap-login {
inet_listener imap {
listen = $imap_listener_adresses
#port = 143
}
inet_listener imaps {
listen = $imaps_listener_adresses
#port = 993
#ssl = yes
}
# Minimum number of processes that always should be available to accept more client connections.
process_min_avail = 16
}
EOF
replace_or_append_code_block "service imap-login" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
read -r -d '' NEW_BLOCK <<EOF
service pop3-login {
inet_listener pop3 {
listen = $pop_listener_adresses
#port = 110
}
inet_listener pop3s {
listen = $pops_listener_adresses
#port = 995
#ssl = yes
}
}
EOF
replace_or_append_code_block "service pop3-login" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
read -r -d '' NEW_BLOCK <<EOF
service submission-login {
inet_listener submission {
#port = 587
}
inet_listener submissions {
#port = 465
}
}
EOF
replace_or_append_code_block "service submission-login" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
read -r -d '' NEW_BLOCK <<EOF
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
user = postfix
group = postfix
mode = 0660
}
# Create inet listener only if you can't use the above UNIX socket
#inet_listener lmtp {
# Avoid making LMTP visible for the entire internet
#address =
#port =
#}
}
EOF
replace_or_append_code_block "service lmtp" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
read -r -d '' NEW_BLOCK <<EOF
service imap {
# tell imap to do post-login lookup using a socket called "imap-postlogin"
executable = imap post-login
# Most of the memory goes to mmap()ing files. You may need to increase this
# limit if you have huge mailboxes.
#vsz_limit = $default_vsz_limit
# Max. number of IMAP processes (connections)
#process_limit = 1024
}
EOF
replace_or_append_code_block "service imap" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
read -r -d '' NEW_BLOCK <<EOF
service pop3 {
# tell imap to do post-login lookup using a socket called "imap-postlogin"
executable = pop3 post-login
# Max. number of POP3 processes (connections)
#process_limit = 1024
}
EOF
replace_or_append_code_block "service pop3" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
read -r -d '' NEW_BLOCK <<EOF
service submission {
# Max. number of SMTP Submission processes (connections)
#process_limit = 1024
}
EOF
replace_or_append_code_block "service submission" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
if ${xmpp_listener} ; then
read -r -d '' NEW_BLOCK <<EOF
service auth {
# Auth Listener (XMPP - Jabber)
inet_listener {
address = $xmpp_listener_addresses
port = $xmpp_listener_port
}
# auth_socket_path points to this userdb socket by default. It's typically
# used by dovecot-lda, doveadm, possibly imap process, etc. Users that have
# full permissions to this socket are able to get a list of all usernames and
# get the results of everyone's userdb lookups.
#
# The default 0666 mode allows anyone to connect to the socket, but the
# userdb lookups will succeed only if the userdb returns an "uid" field that
# matches the caller process's UID. Also if caller's uid or gid matches the
# socket's uid or gid the lookup succeeds. Anything else causes a failure.
#
# To give the caller full permissions to lookup all users, set the mode to
# something else than 0666 and Dovecot lets the kernel enforce the
# permissions (e.g. 0777 allows everyone full permissions).
unix_listener auth-userdb {
mode = 0666
user = dovecot
group = dovecot
}
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/dovecot-auth {
mode = 0666
user = postfix
group = postfix
}
}
EOF
else
read -r -d '' NEW_BLOCK <<'EOF'
service auth {
# auth_socket_path points to this userdb socket by default. It's typically
# used by dovecot-lda, doveadm, possibly imap process, etc. Users that have
# full permissions to this socket are able to get a list of all usernames and
# get the results of everyone's userdb lookups.
#
# The default 0666 mode allows anyone to connect to the socket, but the
# userdb lookups will succeed only if the userdb returns an "uid" field that
# matches the caller process's UID. Also if caller's uid or gid matches the
# socket's uid or gid the lookup succeeds. Anything else causes a failure.
#
# To give the caller full permissions to lookup all users, set the mode to
# something else than 0666 and Dovecot lets the kernel enforce the
# permissions (e.g. 0777 allows everyone full permissions).
unix_listener auth-userdb {
mode = 0666
user = dovecot
group = dovecot
}
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/dovecot-auth {
mode = 0666
user = postfix
group = postfix
}
}
EOF
fi
replace_or_append_code_block "service auth" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
read -r -d '' NEW_BLOCK <<EOF
service auth-worker {
# Auth worker process is run as root by default, so that it can access
# /etc/shadow. If this isn't necessary, the user should be changed to
# $SET:default_internal_user.
#user = root
}
EOF
replace_or_append_code_block "service auth-worker" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
read -r -d '' NEW_BLOCK <<EOF
service dict {
# If dict proxy is used, mail processes should have access to its socket.
# For example: mode=0660, group=vmail and global mail_access_groups=vmail
unix_listener dict {
#mode = 0600
#user =
#group =
}
}
EOF
replace_or_append_code_block "dict" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
# if grep -qE "^\s*service\s+auth\s*{" "${_conf_file}"; then
# replace_code_block "service auth" "${NEW_BLOCK}" "${_conf_file}"
#
# if [[ $? -gt 0 ]]; then
# _failed=true
# fi
# else
# echo -e "\n${NEW_BLOCK}" >> "${_conf_file}"
# fi
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Adjusting Adjusting file ${_conf_file} failed"
error "$(cat "${_conf_file}")"
echo ""
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Interupted by user"
fi
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-master.conf
## -
## - default_process_limit = 1024
## - default_client_limit = 10240
## -
## - default_vsz_limit = 512M
## -
## - !! Bemerkung !!
## -
## - Das Hochsetzen des default_client_limit Parameters auf einen Wert größer
## - als 1024 geht nur dann wenn auch die Anzahl der zulässigen "open files"
## - (default = 1024) geändert wird.
## -
## -
## - Systemd System:
## - ===============
## -
## - In der service datei (z.Bsp. /etc/systemd/system/multi-user.target.wants/dovecot.service)
## - den Wert 'LimitNOFILE' hochsetzen:
## -
## - LimitNOFILE=32768 (must be greater or equal of 'default_client_limit')
## -
## - systemctl daemon-reload
## - systemctl restart dovecot.service
## -
## - Im Falle von LX containern muss zusätzlich auf dem hostsystem
## - in der datei '/etc/systemd/system.conf' der Wert für 'DefaultLimitNOFILE'
## - hochgesetzt werden.
## -
## - System V systems:
## - =================
## - Das Hochsetzen des default_client_limit Parameters auf einen Wert größer
## - als 1024 geht nur dann wenn auch die Anzahl der zulässigen "open files"
## - (default = 1024) geändert wird. Z.Bsp. in der Datei /etc/init.d/dovecot
## - durch Einfügen der zeile:
## - ulimit -n 32768
## -
## - Linux VServer:
## - put the following lines into /etc/security/limits.conf
## -
## - @staff hard nofile 32768
## - root hard nofile 32768
## -
## - !! Mybe you have also create file /etc/vservers/*/ulimits/nofiles.hard
## - with the same contents:
## -
## - @staff hard nofile 32768
## - @adm hard nofile 32768
## - root hard nofile 32768
## -
## - see also http://linux-vserver.org/Ulimit_Nofiles
## -
## -
## -
## - service auth {
## -
## - # Auth Listener (XMPP - Jabber)
## - inet_listener {
## - address = $xmpp_listener_addresses
## - port = $xmpp_listener_port
## - }
## - ..
## - unix_listener auth-userdb {
## - mode = 0666
## - user = dovecot
## - group = dovecot
## - }
## - ..
## - unix_listener /var/spool/postfix/private/dovecot-auth {
## - mode = 0666
## - user = postfix
## - group = postfix
## - }
## - ..
## - }
## -
## - service imap-login {
## - inet_listener imap {
## - address = $imap_listener_adresses
## - ..
## - }
## - inet_listener imaps {
## - address = $imaps_listener_adresses
## - ..
## - }
## -
## - process_min_avail = 16
## - }
## -
## - service pop3-login {
## - inet_listener pop3 {
## - address = $pop_listener_adresses
## - ..
## - }
## - inet_listener pop3s {
## - address = $pops_listener_adresses
## - ..
## - }
## - }
## -
echononl " Adjusting file 10-master.conf.."
perl -i.ORIG -n -p -e "s#^([ ]*)(unix_listener\ +auth-userdb.*)#\1\2\n\1 mode = 0666\n\1 user = dovecot\n\1 group = dovecot#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)(\#.*Postfix.*smtp-auth.*)#\1\2\n\1unix_listener /var/spool/postfix/private/dovecot-auth {\n\1 mode = 0666\n\1 user = postfix\n\1 group = postfix\n\1}#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)(inet_listener\ +imap\ .*)#\1\2\n\1 address = $imap_listener_adresses#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)(inet_listener\ +imaps.*)#\1\2\n\1 address = $imaps_listener_adresses#g#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)(\#?process_min_avail\ ?=.*)#\1\#\# \2\n\1process_min_avail = 16#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)(inet_listener\ +pop3\ .*)#\1\2\n\1 address = $pop_listener_adresses#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)(inet_listener\ +pop3s.*)#\1\2\n\1 address = $pops_listener_adresses#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
if $xmpp_listener ; then
perl -i -n -p -e "s#^([ ]*)(service auth\s+\{.*)#\1\2\n\n \# Auth Listener (XMPP - Jabber)\n inet_listener {\n address = $xmpp_listener_addresses\n port = $xmpp_listener_port\n }\n#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
fi
## - setting default prozcess/client limit
## -
perl -i -n -p -e "s#^([ ]*\#?[ ]*)(default_process_limit.*)#\1\2\ndefault_process_limit = 1024#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
perl -i -n -p -e "s#^([ ]*\#?[ ]*)(default_client_limit.*)#\1\2\ndefault_client_limit = 10240#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
perl -i -n -p -e "s#^([ ]*\#?[ ]*)(default_vsz_limit.*)#\1\2\ndefault_vsz_limit = 512M#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-master.conf
blank_line
echononl " Create Cert/Key Directory '$cert_base_dir'.."
if [[ ! -d "$cert_base_dir" ]] ; then
mkdir -p "$cert_base_dir" > $log_file 2>&1
if [[ $? -eq 0 ]] ; then
echo -e "$rc_done"
echononl " Change Permissions for Cert/Key Directory '$cert_base_dir'.."
chmod 755 "$cert_base_dir" > $log_file 2>&1
if [[ $? -eq 0 ]] ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "$(cat "$log_file")"
fi
else
echo -e "$rc_failed"
error "$(cat "$log_file")"
fi
else
echo -e "$rc_skipped"
fi
## - Since dovecot version 2.3.x SSL DH parameters will be stored
## - permanently on filesystem. So we have to create such a file
## -
## - openssl dhparam -out /etc/postfix/ssl/dh_4096.pem`
## -
echononl " Create SSL DH parameters '$dh_pem_file'.."
if [[ $dovecot_major_version -ge 3 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -ge 3 ]] ); then
if [[ ! -f "$dh_pem_file" ]] ; then
echo -en "$rc_wait"
if [[ "$os_dist" = "debian" ]] && [[ $os_version -gt 11 ]] ; then
openssl dhparam -out "$dh_pem_file" 4096 > /dev/null 2>&1
else
openssl dhparam -dsaparam -out "$dh_pem_file" 4096 > /dev/null 2>&1
fi
if [[ $? -eq 0 ]]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating DH parameter file '$dh_pem_file' failed."
fi
else
echo -e "$rc_skipped"
fi
else
echo -e "$rc_skipped"
fi
# edit /usr/local/dovecot/etc/dovecot/conf.d/10-ssl.conf
#
_failed=false
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
# edit /usr/local/dovecot/etc/dovecot/conf.d/10-ssl.conf
#
# ssl_server {
#
# ssl = required
#
# # Preferred permissions: root:root 0444
# cert_file = $server_cert
#
# # Preferred permissions: root:root 0400
# key_file = $server_key
#
# # Path to the Diffie-Hellman parameters file. This setting isn't needed if using only ECDSA certificates.
# #
# # You can generate a new parameters file by, for example, running
# #
# # openssl dhparam -out dh.pem 4096
# #
# # on a machine with sufficient entropy (this may take some time).
# dh_file = $dh_pem_file
#
# # SSL ciphers to use
# ssl_cipher_list = ${ssl_cipher_list}
#
#
# # Whether to give preference to the server's cipher list over a client's list (server)
# # or vice versa (client)
# #
# # For TLSv1.3 server ciphers should not longer be preferred
# prefer_ciphers = client
#
# # The minimum SSL protocol version Dovecot accepts.
# #
# # This setting is used for both incoming and outgoing SSL connections.
# min_protocol = TLSv1.2
# }
echononl " Adjusting file $(basename "${_conf_file}").."
:> "${log_file}"
read -r -d '' NEW_BLOCK <<EOF
# Specifying SSL server settings.
ssl_server {
ssl = required
# Preferred permissions: root:root 0444
cert_file = $server_cert
# Preferred permissions: root:root 0400
key_file = $server_key
# Path to the Diffie-Hellman parameters file. This setting isn't needed if using only ECDSA certificates.
#
# You can generate a new parameters file by, for example, running
#
# openssl dhparam -out dh.pem 4096
#
# on a machine with sufficient entropy (this may take some time).
dh_file = $dh_pem_file
# SSL ciphers to use
ssl_cipher_list = ${ssl_cipher_list}
# Whether to give preference to the server's cipher list over a client's list (server)
# or vice versa (client)
#
# For TLSv1.3 server ciphers should not longer be preferred
prefer_ciphers = client
}
EOF
replace_or_append_code_block "ssl_server" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
_param="ssl_min_protocol"
_val="TLSv1.2"
if grep -qE "^\s*${_param}\s*=" "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \
"${_conf_file}" >> "${log_file}" 2>&1 || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# The minimum SSL protocol version Dovecot accepts.
#
# This setting is used for both incoming and outgoing SSL connections.
${_param} = ${_val}
EOF
fi
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Adjusting Adjusting file ${_conf_file} failed"
error "$(cat "${log_file}")"
echo ""
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Interupted by user"
fi
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-ssl.conf
## -
## - ssl = required
## -
## - ssl_cert = <$server_cert
## - ssl_key = <$server_key
## -
## - # - 'ssl_dh_parameters_length' is obsolete and no longer needed
## - #ssl_dh_parameters_length = 2048
## -
## - # - 'ssl_protocols has been' replaced by ssl_min_protocol
## - #ssl_protocols = !SSLv3
## - ssl_min_protocol = TLSv1.2
## -
## - ssl_cipher_list = ${ssl_cipher_list}
## -
## - ssl_prefer_server_ciphers = yes
## -
## -
## - there are another possibilities to handle certs, but this did'nt work
## - as i expected..
## - #local_name imap.warenform.de {
## - # ssl_cert = <$imap_cert
## - # ssl_key = <$imap_key
## - #}
## - #local_name pop.warenform.de {
## - # ssl_cert = <$pop_cert
## - # ssl_key = <$pop_key
## - #}
## -
echononl " Backup file $(basename "${_conf_file}").."
if [[ ! -f "${_conf_file}.ORIG" ]] ; then
cp -a "${_conf_file}" "${_conf_file}.ORIG" > ${log_file} 2>&1
if [[ $? -gt 0 ]] ; then
echo -e "$rc_failed"
error "$(cat $log_file)"
else
echo -e "$rc_done"
fi
else
echo -e "$rc_skipped"
fi
:> "${log_file}"
echononl " Adjusting file $(basename "${_conf_file}").."
_param="ssl"
_val="required"
if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \
"${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# SSL/TLS support: yes, no, required.
${_param} = ${_val}
EOF
fi
_param="ssl_cert"
_val="<$server_cert"
if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \
"${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before
# dropping root privileges, so keep the key file unreadable by anyone but
# root. Included doc/mkcert.sh can be used to easily generate self-signed
# certificate, just make sure to update the domains in dovecot-openssl.cnf
${_param} = ${_val}
EOF
fi
_param="ssl_key"
_val="<$server_key"
if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \
"${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
${_param} = ${_val}
EOF
fi
if [[ $dovecot_major_version -ge 3 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -ge 3 ]] ); then
if [[ ! -f "$dh_pem_file" ]]; then
if [[ -f "/etc/postfix/ssl/dh_2048.pem" ]]; then
dh_pem_file="/etc/postfix/ssl/dh_2048.pem"
fi
fi
if [[ -f "$dh_pem_file" ]]; then
_param="ssl_dh"
_val="<$dh_pem_file"
if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \
"${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# SSL DH parameters
# Generate new params with \`openssl dhparam -out /etc/dovecot/dh.pem 4096\`
# Or migrate from old ssl-parameters.dat file with the command dovecot
# gives on startup when ssl_dh is unset.
${_param} = ${_val}
EOF
fi
else
_failed=true
fi
else
perl -i -n -p -e "s#^([ ]*)\#?(ssl_dh_parameters_length\ ?=.*)#\1\#\# \2\nssl_dh_parameters_length = 2048#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf || _failed=true
fi
_param="ssl_min_protocol"
_val="TLSv1.2"
if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \
"${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# The minimum SSL protocol version Dovecot accepts.
${_param} = ${_val}
EOF
fi
echo "ssl_min_protocol: done"
# - Replace only the first occurence of the match
# -
# - Example:
# - # Replace first occurence of 'width: .*' in file 'filename.css'
# -
# - perl -pi -e '$a=1 if(!$a && s/(width:).*;/$1 100%;/);' filename.css
# -
#perl -i -n -p -e "\$a=1 if(!\$a && s#^([ ]*)\#?(ssl_cipher_list\ ?=.*)#\1\#\# \2\nssl_cipher_list = ${ssl_cipher_list}#);" \
# /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf || _failed=true
perl -i -n -p -e "\$a=1 if(!\$a && s#^([ ]*)\#?(ssl_cipher_list\ ?=.*)#ssl_cipher_list = ${ssl_cipher_list}#);" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf || _failed=true
echo "ssl_cipher_list: done"
_param="ssl_min_protocol"
_val="TLSv1.2"
if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \
"${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# The minimum SSL protocol version Dovecot accepts.
${_param} = ${_val}
EOF
fi
_param="ssl_prefer_server_ciphers"
_val="no"
if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then
perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \
"${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Prefer the server's order of ciphers over client's.
${_param} = ${_val}
EOF
fi
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Adjusting '$(basename "${_conf_file}") failed"
echo ""
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Interupted by user"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-ssl.conf
# edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
#
_failed=false
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
# edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
#
# mail_home = /var/vmail/%{user | domain}/%{user | username}
# mail_driver = Maildir
# mail_path = ~/Maildir
#
# mail_uid = vmail
# mail_gid = vmail
#
# first_valid_uid = ${vmail_uid}
# last_valid_uid = ${vmail_uid}
#
# first_valid_gid = ${vmail_gid}
# last_valid_gid = ${vmail_gid}
#
# mail_temp_dir = /var/vmail/tmp
#
# auth_socket_path = /run/dovecot/auth-userdb
#
# mail_plugins = quota acl
#
# mailbox_list_index
#
echononl " Adjusting file '$(basename "${_conf_file}")'.."
:> "${log_file}"
if grep -qE '^\s*mail_home\s*=' "${_conf_file}" \
|| grep -qE '^\s*mail_driver\s*=' "${_conf_file}" \
|| grep -qE '^\s*mail_path\s*=' "${_conf_file}" ; then
replace_variable \
"mail_home" \
'/var/vmail/%{user | domain}/%{user | username}' \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
replace_variable \
"mail_driver" \
'Maildir' \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
replace_variable \
"mail_path" \
'~/Maildir' \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
else
cat <<'EOF' >> "${_conf_file}" || _failed=true
mail_home= /var/vmail/%{user | domain}/%{user | username}'
mail_driver = Maildir
mail_path = ~/Maildir
EOF
if [[ $? -gt 0 ]] ; then
_failed=true
fi
fi
if grep -qE '^\s*mail_uid\s*=' "${_conf_file}" \
|| grep -qE '^\s*mail_uid\s*=' "${_conf_file}" ; then
replace_variable \
"mail_uid" \
'vmail' \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
replace_variable \
"mail_gid" \
'vmail' \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
else
cat <<'EOF' >> "${_conf_file}" || _failed=true
# System user and group used to access mails.
mail_uid = vmail
mail_gid = vmail
EOF
if [[ $? -gt 0 ]] ; then
_failed=true
fi
fi
if grep -qE '^\s*first_valid_uid\s*=' "${_conf_file}" \
|| grep -qE '^\s*last_valid_uid\s*=' "${_conf_file}" ; then
replace_variable \
"first_valid_uid" \
"${vmail_uid}" \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
replace_variable \
"last_valid_uid" \
"${vmail_uid}" \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Valid UID range for users allowed to login
first_valid_uid = ${vmail_uid}
last_valid_uid = ${vmail_uid}
EOF
if [[ $? -gt 0 ]] ; then
_failed=true
fi
fi
if grep -qE '^\s*first_valid_gid\s*=' "${_conf_file}" \
|| grep -qE '^\s*last_valid_gid\s*=' "${_conf_file}" ; then
replace_variable \
"first_valid_gid" \
"${vmail_gid}" \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
replace_variable \
"last_valid_gid" \
"${vmail_gid}" \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Valid GID range for users allowed to login
first_valid_gid = ${vmail_gid}
last_valid_gid = ${vmail_gid}
EOF
if [[ $? -gt 0 ]] ; then
_failed=true
fi
fi
if grep -qE '^\s*mail_temp_dir\s*=' "${_conf_file}" ; then
replace_variable \
"mail_temp_dir" \
"/var/vmail/tmp" \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
else
cat <<EOF >> "${_conf_file}" || _failed=true
# The directory in which LDA/LMTP will temporarily store incoming message data
# that is above 128kB in size.
mail_temp_dir = /var/vmail/tmp
EOF
if [[ $? -gt 0 ]] ; then
_failed=true
fi
fi
if grep -qE '^\s*auth_socket_path\s*=' "${_conf_file}" ; then
replace_variable \
"auth_socket_path" \
"/run/dovecot/auth-userdb" \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
else
cat <<EOF >> "${_conf_file}" || _failed=true
# The UNIX socket path to the master authentication server for finding users.
auth_socket_path = /run/dovecot/auth-userdb
EOF
if [[ $? -gt 0 ]] ; then
_failed=true
fi
fi
if grep -qE '^\s*mail_plugins\s*=' "${_conf_file}" ; then
replace_variable \
"mail_plugins" \
"quota acl" \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
else
cat <<EOF >> "${_conf_file}" || _failed=true
# A list of mail plugins to load.
mail_plugins = quota acl
EOF
if [[ $? -gt 0 ]] ; then
_failed=true
fi
fi
if grep -qE '^\s*mailbox_list_index\s*=' "${_conf_file}" ; then
replace_variable \
"mailbox_list_index" \
"yes" \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Dovecot indexes live at the root of user's mailbox storage, and allows quick lookup
# of mailbox status instead of needing to open all mailbox indexes separately.
#
# Enabling this optimizes the server reply to IMAP STATUS commands, which are commonly
# issued by clients. This also needs to be enabled if you wish to enable the
# IMAP NOTIFY extension.
mailbox_list_index = yes
EOF
if [[ $? -gt 0 ]] ; then
_failed=true
fi
fi
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Adjusting '$(basename "${_conf_file}") failed"
echo ""
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Interupted by user"
fi
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
## -
## - mail_location = maildir:/var/vmail/%d/%n/Maildir
## -
## - mail_uid = vmail
## - mail_gid = vmail
## -
## - first_valid_uid = 5000
## - last_valid_uid = 5000
## -
## - mail_temp_dir = /var/vmail/tmp
## -
## - first_valid_gid = 5000
## - last_valid_gid = 5000
## -
## - auth_socket_path = /run/dovecot/auth-userdb
## - mail_plugins = quota acl | mail_plugins = quota acl expire
## -
## - mailbox_list_index = yes
## -
echononl " Adjusting file 10-mail.conf"
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(mail_location\ +=.*)#\1\#\# \2\n\1mail_location = maildir:/var/vmail/%d/%n/Maildir#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_uid.*)#\1\#\# \2\n\1mail_uid = vmail#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_gid.*)#\1\#\# \2\n\1mail_gid = vmail#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_temp_dir.*)#\1\#\# \2\n\1mail_temp_dir = /var/vmail/tmp#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(first_valid_uid.*)#\1\#\# \2\n\1first_valid_uid = 5000#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(last_valid_uid.*)#\1\#\# \2\n\1last_valid_uid = 5000#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(first_valid_gid.*)#\1\#\# \2\n\1first_valid_gid = 5000#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(last_valid_gid.*)#\1\#\# \2\n\1last_valid_gid = 5000#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(auth_socket_path\ +=.*)#\1\#\# \2\n\1auth_socket_path = /run/dovecot/auth-userdb#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
if $plugin_expire ; then
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota acl expire#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
else
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota acl#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
fi
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mailbox_list_index\s*=.*)#\1\#\# \2\n\1mailbox_list_index = yes#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file '10-mail.conf' failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
echononl " Create TEMP directory '/var/vmail/tmp' .."
if [[ ! -d /var/vmail/tmp ]] ; then
mkdir /var/vmail/tmp > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating TEMP directory '/var/vmail/tmp' failed."
fi
else
echo -e "$rc_skipped"
fi
echononl " Change ownerchip of directory '/var/vmail/tmp' .."
chown vmail:vmail /var/vmail/tmp > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Changing ownerchip of directory '/var/vmail/tmp' failed."
fi
blank_line
# modify /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
#
#
_failed=false
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Modify file '$(basename "${_conf_file}")'.."
# modify /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
#
# namespace inbox {
# type = private
# separator = /
# hidden = no
# list = yes
# subscriptions = yes
# }
if grep -qE "^\s*namespace\s+inbox\s*{" "${_conf_file}"; then
read -r -d '' NEW_BLOCK <<EOF
namespace inbox {
# The namespace type. One of:
#
# public Contains public shared mailboxes.
# private Typically contains only user's own private mailboxes.
# shared Contains other users' user shared mailboxes.
#
# Default: private
type = private
# Specifies the hierarchy separator for the namespace.
#
# Default: "." for Maildir; "/" for other mbox formats
#
# The separator is a single character, which can't then otherwise be used in folder names.
# The commonly used separators are . and /, but other separators can be used as well. For
# example ^ is less likely to be found in normal folder names.
#
# Recommended value is to leave it empty and accept the default value.
separator = /
# Specifies prefix for namespace.
#
# Must end with namespace_separator.
#
# Default: [none]
#prefix =
# If yes, this namespace will be considered the one holding the INBOX folder.
#
# There can be only one namespace defined like this.
inbox = yes
# If yes, namespace will be hidden from IMAP NAMESPACE (RFC 2342) command.
hidden = no
# Include this namespace in LIST output when listing its parent's folders.
#
# One of:
# children Namespace prefix list listed only if it has child mailboxes.
#
# no Namespace and mailboxes not listed unless listing requests explicitly
# mailboxes under the namespace prefix.
#
# yes Namespace and mailboxes are always listed.
#
# It is still possible to list the namespace's folders by explicitly asking for them.
# For example, if this setting is no, using LIST "" * with namespace prefix "lazy-expunge/"
# won't list it, but using LIST "" lazy-expunge/* lists all folders under it.
#
# Default: yes
list = yes
# Whether subscriptions are stored in this namespace.
#
# This is usually no for shared namespaces so that the shared folders' subscriptions are
# stored in the user's primary subscriptions file. If no, the subscriptions are stored in
# the first parent namespace (based on the prefix) that has this setting enabled.
#
# Example: If this setting is no for a namespace with prefix=foo/bar/, Dovecot first sees
# if there's a prefix=foo/ namespace with subscriptions=yes and then a namespace with an
# empty prefix. If neither is found, an error is given.
#
# Default: yes
subscriptions = yes
}
EOF
replace_or_append_code_block "namespace inbox" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
else
cat <<EOF >> "${_conf_file}" 2> "${log_file}"
# Namespaces
#
# Dovecot supports fully configurable, hierarchical namespaces, which can use different storage drivers.
#
# Their original and primary purpose is to provide Namespace IMAP extension (RFC 2342) support, which
# allows giving IMAP clients hints about where to locate mailboxes and whether they're private, shared
# or public.
#
# Dovecot namespaces can be used for several other purposes too:
#
# Changing the Hierarchy Separators
# Providing backwards compatibility when switching from another IMAP server
# Provides support for public shared mailboxes and user shared mailboxes mailboxes
# Allows having mails in multiple different locations with possibly different formats
#
# These different locations and drivers are presented to the client as a single tree.
#
# Each namespace has:
#
# prefix (usually empty or "INBOX.")
# namespace separator (usually '/' or '.')
# 0 or more folders
#
# There must be one namespace where the case-insensitive folder named INBOX exists.
#
# All visible namespaces must have the same separator.
#
# Inside each namespace there is a list of folders, which form a sub-hierarchy.
namespace inbox {
# The namespace type. One of:
#
# public Contains public shared mailboxes.
# private Typically contains only user's own private mailboxes.
# shared Contains other users' user shared mailboxes.
#
# Default: private
type = private
# Specifies the hierarchy separator for the namespace.
#
# Default: "." for Maildir; "/" for other mbox formats
#
# The separator is a single character, which can't then otherwise be used in folder names.
# The commonly used separators are . and /, but other separators can be used as well. For
# example ^ is less likely to be found in normal folder names.
#
# Recommended value is to leave it empty and accept the default value.
separator = /
# Specifies prefix for namespace.
#
# Must end with namespace_separator.
#prefix =
# If yes, this namespace will be considered the one holding the INBOX folder.
#
# There can be only one namespace defined like this.
inbox = yes
# If yes, namespace will be hidden from IMAP NAMESPACE (RFC 2342) command.
hidden = no
# Include this namespace in LIST output when listing its parent's folders.
#
# One of:
# children Namespace prefix list listed only if it has child mailboxes.
#
# no Namespace and mailboxes not listed unless listing requests explicitly
# mailboxes under the namespace prefix.
#
# yes Namespace and mailboxes are always listed.
#
# It is still possible to list the namespace's folders by explicitly asking for them.
# For example, if this setting is no, using LIST "" * with namespace prefix "lazy-expunge/"
# won't list it, but using LIST "" lazy-expunge/* lists all folders under it.
#
# Default: yes
list = yes
# Whether subscriptions are stored in this namespace.
#
# This is usually no for shared namespaces so that the shared folders' subscriptions are
# stored in the user's primary subscriptions file. If no, the subscriptions are stored in
# the first parent namespace (based on the prefix) that has this setting enabled.
#
# Example: If this setting is no for a namespace with prefix=foo/bar/, Dovecot first sees
# if there's a prefix=foo/ namespace with subscriptions=yes and then a namespace with an
# empty prefix. If neither is found, an error is given.
#
# Default: yes
subscriptions = yes
}
EOF
if [[ $? -gt 0 ]]; then
_failed=true
fi
fi # if grep -qE "^\s*namespace\s+inbox\s*{" "${_conf_file}"; then
read -r -d '' NEW_BLOCK <<EOF
namespace shared {
type = shared
separator = /
# Mailboxes are visible under "shared/user@domain/"
# %%n, %%d and %%u are expanded to the destination user.
prefix = shared/%%u/
# Mail location setting
mail_home = /var/vmail/%{user | domain}/%{user | username}
mail_driver = Maildir
mail_path = mail_path = ~/Maildir
mail_index_private_path = ~/Maildir/shared/%{owner_user}
# Use the default namespace for saving subscriptions.
subscriptions = no
# Include this namespace in LIST output when listing its parent's folders.
#
# One of:
# children Namespace prefix list listed only if it has child mailboxes.
#
# no Namespace and mailboxes not listed unless listing requests explicitly
# mailboxes under the namespace prefix.
#
# yes Namespace and mailboxes are always listed.
#
# It is still possible to list the namespace's folders by explicitly asking for them.
# For example, if this setting is no, using LIST "" * with namespace prefix "lazy-expunge/"
# won't list it, but using LIST "" lazy-expunge/* lists all folders under it.
#
# Default: yes
list = children
}
EOF
# Replace or expand only if namespace block contains "type = value"
#
replace_or_append_code_block "namespace" "${NEW_BLOCK}" "${_conf_file}" "type" "shared" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Adjusting Adjusting file ${_conf_file} failed"
error "$(cat "${log_file}")"
echo ""
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Interupted by user"
fi
else
echononl " Modify file '$(basename "${_conf_file}")'.."
## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
## -
## - comment out namespace section "namespace inbox". we will create namespaces later.
## - in detail, tha means comment out 3 lines:
## - namespace inbox {
## - ..
## - inbox = yes
## - ..
## - }
## -
# _tmp_file="$(mktemp)"
# > $_tmp_file
# while IFS='' read -r _line || [[ -n $_line ]] ; do
#
# if echo "$_line" | grep -i -E "^\s*namespace\s+inbox\s+" > /dev/null 2>&1 ; then
# echo "## $_line" >> $_tmp_file
# _found=true
# continue
# fi
#
# if $_found && echo "$_line" | grep -i -E "^\s*}" > /dev/null 2>&1 ; then
# echo "## $_line" >> $_tmp_file
# _found=false
# continue
# fi
#
# if $_found ; then
# echo "## $_line" >> $_tmp_file
# else
# echo "$_line" >> $_tmp_file
# fi
# done < "/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf"
# if [[ "$?" != "0" ]] ; then
# _failed=true
# fi
# mv /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf \
# /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf.TMP
# if [[ "$?" != "0" ]] ; then
# _failed=true
# fi
# mv $_tmp_file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf
# if [[ "$?" != "0" ]] ; then
# _failed=true
# fi
# chmod 644 /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf
# if [[ "$?" != "0" ]] ; then
# _failed=true
# fi
#
#
# #perl -i -n -p -e "s#^([ ]*)(namespace\ +inbox\ +{\ *)#\1\#\#\ \2#g" \
# # /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
# #perl -i -n -p -e "s#^([ ]*)(inbox\ +=\ +yes\ *)#\1\#\#\ \2#g" \
# # /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
# #perl -i -n -p -e "s#^([ ]*)(}\ *)#\1\#\#\ \2#g" \
# # /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
#
# if ! $_failed ; then
# echo -e "$rc_done"
# else
# echo -e "$rc_failed"
# fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf failed"
# fi
## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
## -
## - Add or Replace 'namespace inbox' type private
## -
## - namespace inbox {
## - # Namespace type: private, shared or public
## - type = private
## -
## - # Hierarchy separator to use. You should use the same separator for all
## - # namespaces or some clients get confused. '/' is usually a good one.
## - # The default however depends on the underlying mail storage format.
## - #separator =
## - separator = /
## -
## - # Prefix required to access this namespace. This needs to be different for
## - # all namespaces. For example "Public/".
## - #prefix =
## - prefix =
## -
## - # Physical location of the mailbox. This is in same format as
## - # mail_location, which is also the default for it.
## - #location =
## -
## - # There can be only one INBOX, and this setting defines which namespace
## - # has it.
## - #inbox = no
## - inbox = yes
## -
## - # If namespace is hidden, it's not advertised to clients via NAMESPACE
## - # extension. You'll most likely also want to set list=no. This is mostly
## - # useful when converting from another server with different namespaces which
## - # you want to deprecate but still keep working. For example you can create
## - # hidden namespaces with prefixes "~/mail/", "~%u/mail/" and "mail/".
## - #hidden = no
## -
## - # Show the mailboxes under this namespace with LIST command. This makes the
## - # namespace visible for clients that don't support NAMESPACE extension.
## - # "children" value lists child mailboxes, but hides the namespace prefix.
## - #list = yes
## -
## - # Namespace handles its own subscriptions. If set to "no", the parent
## - # namespace handles them (empty prefix should always have this as "yes")
## - #subscriptions = yes
## - }
echononl " Modify file '$(basename "${_conf_file}")'.."
if grep -qE "^\s*namespace\s+inbox\s*{" "${_conf_file}"; then
read -r -d '' NEW_BLOCK <<EOF
namespace inbox {
# Namespace type: private, shared or public
type = private
# Hierarchy separator to use. You should use the same separator for all
# namespaces or some clients get confused. '/' is usually a good one.
# The default however depends on the underlying mail storage format.
#separator =
separator = /
# Prefix required to access this namespace. This needs to be different for
# all namespaces. For example "Public/".
#prefix =
prefix =
# Physical location of the mailbox. This is in same format as
# mail_location, which is also the default for it.
#location =
# There can be only one INBOX, and this setting defines which namespace
# has it.
#inbox = no
inbox = yes
# If namespace is hidden, it's not advertised to clients via NAMESPACE
# extension. You'll most likely also want to set list=no. This is mostly
# useful when converting from another server with different namespaces which
# you want to deprecate but still keep working. For example you can create
# hidden namespaces with prefixes "~/mail/", "~%u/mail/" and "mail/".
#hidden = no
# Show the mailboxes under this namespace with LIST command. This makes the
# namespace visible for clients that don't support NAMESPACE extension.
# "children" value lists child mailboxes, but hides the namespace prefix.
#list = yes
# Namespace handles its own subscriptions. If set to "no", the parent
# namespace handles them (empty prefix should always have this as "yes")
#subscriptions = yes
}
EOF
replace_or_append_code_block "namespace inbox" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
else
cat <<EOF >> "${_conf_file}" 2> "${log_file}"
# If you need to set multiple mailbox locations or want to change default
# namespace settings, you can do it by defining namespace sections.
#
# You can have private, shared and public namespaces. Private namespaces
# are for user's personal mails. Shared namespaces are for accessing other
# users' mailboxes that have been shared. Public namespaces are for shared
# mailboxes that are managed by sysadmin. If you create any shared or public
# namespaces you'll typically want to enable ACL plugin also, otherwise all
# users can access all the shared mailboxes, assuming they have permissions
# on filesystem level to do so.
namespace inbox {
# Namespace type: private, shared or public
type = private
# Hierarchy separator to use. You should use the same separator for all
# namespaces or some clients get confused. '/' is usually a good one.
# The default however depends on the underlying mail storage format.
#separator =
separator = /
# Prefix required to access this namespace. This needs to be different for
# all namespaces. For example "Public/".
#prefix =
prefix =
# Physical location of the mailbox. This is in same format as
# mail_location, which is also the default for it.
#location =
# There can be only one INBOX, and this setting defines which namespace
# has it.
#inbox = no
inbox = yes
# If namespace is hidden, it's not advertised to clients via NAMESPACE
# extension. You'll most likely also want to set list=no. This is mostly
# useful when converting from another server with different namespaces which
# you want to deprecate but still keep working. For example you can create
# hidden namespaces with prefixes "~/mail/", "~%u/mail/" and "mail/".
#hidden = no
# Show the mailboxes under this namespace with LIST command. This makes the
# namespace visible for clients that don't support NAMESPACE extension.
# "children" value lists child mailboxes, but hides the namespace prefix.
#list = yes
# Namespace handles its own subscriptions. If set to "no", the parent
# namespace handles them (empty prefix should always have this as "yes")
#subscriptions = yes
}
EOF
if [[ $? -gt 0 ]]; then
_failed=true
fi
fi
cat <<EOF >> "${_conf_file}" 2> "${log_file}"
namespace {
type = shared
separator = /
# Mailboxes are visible under "shared/user@domain/"
# %%n, %%d and %%u are expanded to the destination user.
prefix = shared/%%u/
# Mail location for other users' mailboxes. Note that %variables and ~/
# expands to the logged in user's data. %%n, %%d, %%u and %%h expand to the
# destination user's data.
#location = maildir:%%h/Maildir:INDEX=~/Maildir/shared/%%u
location = maildir:/var/vmail/%%d/%%n/Maildir:INDEX=~/Maildir/shared/%%u
# Use the default namespace for saving subscriptions.
subscriptions = no
# Include this namespace in LIST output when listing its parent's folders.
#
# One of:
# children Namespace prefix list listed only if it has child mailboxes.
#
# no Namespace and mailboxes not listed unless listing requests explicitly
# mailboxes under the namespace prefix.
#
# yes Namespace and mailboxes are always listed.
#
# It is still possible to list the namespace's folders by explicitly asking for them.
# For example, if this setting is no, using LIST "" * with namespace prefix "lazy-expunge/"
# won't list it, but using LIST "" lazy-expunge/* lists all folders under it.
#
# Default: yes
list = children
}
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adding namespaces to '${_conf_file}' failed"
fi
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Adjusting Adjusting file ${_conf_file} failed"
error "$(cat "${log_file}")"
echo ""
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Interupted by user"
fi
fi # modify /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
# edit /usr/local/dovecot/etc/dovecot/conf.d/15-mailboxes.conf
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjusting file 15-mailboxes.conf.."
echo -e "$rc_not_yet_implemented"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/15-mailboxes.conf
## -
## - Add definitions for mailbox Spam:
## -
## - mailbox Drafts {
## - auto = subscribe
## - special_use = \Drafts
## - }
## -
## - mailbox Trash {
## - auto = subscribe
## - special_use = \Trash
## - }
## -
## - mailbox Sent {
## - auto = subscribe
## - special_use = \Sent
## - }
## -
## - mailbox $spam_folder {
## - auto = subscribe
## - special_use = \Junk
## - }
## -
echononl " Adjusting file 15-mailboxes.conf"
perl -i.ORIG -n -p -e "s#^([ ]*)(mailbox\ +Drafts\ +{.*)#\1\2\n\1 auto = subscribe#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.conf || _failed=true
if [ "$spam_folder" != "Junk" ]; then
if $plugin_expire ; then
perl -i -n -p -e "s#^([ ]*)(mailbox\ +Junk\ +{.*)#\1mailbox $spam_folder {\n\1 auto = subscribe\n\1 special_use = \\\Junk\n\1}\n\1\2#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)(mailbox\ +Junk\ +{.*)#\1\2\n\1 auto = no#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.conf || _failed=true
else
perl -i -n -p -e "s#^([ ]*)(mailbox\ +Junk\ +{.*)#\1mailbox $spam_folder {\n\1 auto = subscribe\n\1 autoexpunge = 30d\n\1 special_use = \\\Junk\n\1}\n\1\2#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)(mailbox\ +Junk\ +{.*)#\1\2\n\1 auto = no\n\1 autoexpunge = 30d#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.conf || _failed=true
fi
else
if $plugin_expire ; then
perl -i -n -p -e "s#^([ ]*)(mailbox\ +$spam_folder\ +{.*)#\1\2\n\1 auto = subscribe#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.conf || _failed=true
else
perl -i -n -p -e "s#^([ ]*)(mailbox\ +$spam_folder\ +{.*)#\1\2\n\1 auto = subscribe\n\1 autoexpunge = 30d#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.conf || _failed=true
fi
fi
if $plugin_expire ; then
perl -i -n -p -e "s#^([ ]*)(mailbox\ +Trash\ +{.*)#\1\2\n\1 auto = subscribe#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.conf || _failed=true
else
perl -i -n -p -e "s#^([ ]*)(mailbox\ +Trash\ +{.*)#\1\2\n\1 auto = subscribe\n\1 autoexpunge = 3d#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.conf || _failed=true
fi
perl -i -n -p -e "s#^([ ]*)(mailbox\ +Sent\ +{.*)#\1\2\n\1 auto = subscribe#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)(mailbox\ +\"Sent Messages\"\ +{.*)#\1\2\n\1 auto = no#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting /usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.conf failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/15-mailboxes.conf
# edit /usr/local/dovecot/etc/dovecot/conf.d/10-auth.conf
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjusting file '10-auth.conf'.."
echo -e "$rc_not_yet_implemented"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-auth.conf
## -
## - disable_plaintext_auth = no
## - auth_mechanisms = $auth_mechanisms
## - !include auth-sql.conf.ext # comment all other includes
## - auth_username_translation = "%@"
## -
echononl " Adjusting file 10-auth.conf"
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(disable_plaintext_auth\ +=.*)#\1\#\# \2\n\1disable_plaintext_auth = yes#" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-auth.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(auth_mechanisms\ +=.*)#\1\#\# \2\n\1auth_mechanisms = $auth_mechanisms#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-auth.conf || _failed=true
perl -i -n -p -e "s#^(\!include\ auth-.*)#\#\1#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-auth.conf || _failed=true
perl -i -n -p -e "s#^\#(\!include\ auth-sql.*)#\1#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-auth.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(auth_username_translation\ +=.*)#\1\#\# \2\n\1auth_username_translation = \"%@\"#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-auth.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-auth.conf failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-auth.conf
# edit /usr/local/dovecot/etc/dovecot/conf.d/auth-sql.conf.ext
#
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjusting file '/auth-sql.conf.ext'.."
echo -e "$rc_not_yet_implemented"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/auth-sql.conf.ext
## -
## - passdb {
## - driver = sql
## -
## -
## - # path for sql configuration file, see example-config/dovecot-sql.conf.ext
## - args = /usr/local/dovecot/etc/dovecot/sql-connect.conf.ext
## - }
## -
## - ..
## -
## - userdb {
## - driver = sql
## - args = /usr/local/dovecot/etc/dovecot/sql-connect.conf.ext
## - }
## -
echononl " Adjusting file auth-sql.conf.ext"
perl -i.ORIG -n -p -e "s#^([ ]*)(args\ ?=.*)#\1\#\# \2\n\1args = /usr/local/dovecot/etc/dovecot/sql-connect.conf.ext#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/auth-sql.conf.ext
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting /usr/local/dovecot-${_version}/etc/dovecot/conf.d/auth-sql.conf.ext failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/auth-sql.conf.ext
# create file /usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf.ext
#
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Create sql configuration file 'sql-connect.conf.ext'.."
echo -e "$rc_not_yet_implemented"
else
## - create sql configuration file
## -
echononl " Create sql configuration file 'sql-connect.conf.ext'.."
if [ "$db_driver" = "pgsql" ]; then
cat <<EOF > /usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf.ext
driver = $db_driver
## - if using unix-socket (host=/run/postgresql) ensure that
## - coresponding entries in pg_hba.cof fits
## - for example
## - local all all md5
## -
connect = host=$dbhost user=$dbuser password=$dbpassword dbname=$dbname
default_pass_scheme = $default_pass_scheme
password_query = SELECT username AS user, password \\
FROM mailbox \\
WHERE username = '%u' AND active = true
user_query = SELECT '/var/vmail/' || maildir AS home, \\
'5000' AS uid, '5000' AS gid \\
FROM mailbox \\
WHERE username = '%u' AND active = true
#WHERE username = substring ('%u' from '#"[^-]+#"_*@%%' for '#') || '@%d' and active = true
## - Query to get a list of all usernames.
## -
iterate_query = SELECT username AS user FROM mailbox
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf.ext failed"
fi
elif [ "$db_driver" = "mysql" ]; then
cat <<EOF > /usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf.ext
driver = $db_driver
connect = host=$dbhost user=$dbuser password=$dbpassword dbname=$dbname
default_pass_scheme = $default_pass_scheme
password_query = SELECT username AS user, password \\
FROM mailbox \\
WHERE username = '%u' AND active = true
user_query = SELECT CONCAT('/var/vmail/',maildir) AS home, \\
'5000' AS uid, '5000' AS gid \\
FROM mailbox \\
WHERE username = '%u' AND active = true
## - Query to get a list of all usernames.
## -
iterate_query = SELECT username AS user FROM mailbox
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf.ext failed"
fi
fi
fi # create file /usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf.ext
# edit /usr/local/dovecot/etc/dovecot/conf.d/10-logging.conf
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjusting file '10-logging.conf'.."
echo -e "$rc_not_yet_implemented"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-logging.conf
## -
## -
## - if running inetd-script:
## -
## - log_path = /var/log/dovecot/dovecot.log
## -
## - or for example
## -
## - log_path = syslog
## - syslog_facility = local1
## - auth_verbose = yes
## - auth_verbose_passwords = plain
## -
## - in conjunction with the the following entries in /etc/rsyslog.conf
## -
## - local1.* -/var/log/dovecot.log
## - local1.info -/var/log/dovecot.info
## - local1.warn -/var/log/dovecot.warn
## - local1.err -/var/log/dovecot.err
## - :msg,contains,"stored mail into mailbox"\
## - -/var/log/dovecot.lmtp
## -
echononl " Adjusting file '10-logging.conf'.."
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(log_path\ ?=.*)#\1\#\# \2\n\1log_path = syslog#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-logging.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(syslog_facility\ ?=.*)#\1\#\# \2\n\1syslog_facility = local1#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-logging.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(auth_verbose\ ?=.*)#\1\#\# \2\n\1auth_verbose = yes#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-logging.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(auth_verbose_passwords\ ?=.*)#\1\#\# \2\n\1auth_verbose_passwords = plain#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-logging.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-logging.conf failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-logging.conf
if $_new ; then
mkdir -p /var/log/dovecot
echo
echononl " Create file /etc/rsyslog.d/dovecot.conf"
cat <<EOF > /etc/rsyslog.d/dovecot.conf
## - dovecot
## -
local1.info -/var/log/dovecot/dovecot.info
local1.warn -/var/log/dovecot/dovecot.warn
local1.err -/var/log/dovecot/dovecot.err
:msg,contains,"stored mail into mailbox" \\
-/var/log/dovecot/dovecot.lmtp
local1.* -/var/log/dovecot/dovecot.log
& stop
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Creating file /etc/rsyslog.d/dovecot.conf failed"
fi
echononl " Restart rsyslog Servive"
if $systemd_support ; then
systemctl restart rsyslog.service > /dev/null 2>&1
else
/etc/init.d/rsyslog restart > /dev/null 2>&1
fi
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Restarting rsyslog failed"
fi
## - logrotate for dovecot log-files
## -
echononl " Create file /etc/logrotate.d/dovecot"
cat <<EOF > /etc/logrotate.d/dovecot
/var/log/dovecot/dovecot.log
/var/log/dovecot/dovecot.info
/var/log/dovecot/dovecot.warn
/var/log/dovecot/dovecot.err
/var/log/dovecot/dovecot.lmtp {
daily
start 0
rotate 7
missingok
notifempty
compress
delaycompress
create 640 root adm
copytruncate
#sharedscripts
#postrotate
#/etc/init.d/dovecot reload > /dev/null
#/bin/kill -usr1 'cat /run/dovecot/master.pid 2>/dev/null' 2>/dev/null || true
#endscript
}
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Creating file /etc/logrotate.d/dovecot failed"
fi
echo
fi
# edit /usr/local/dovecot/etc/dovecot/conf.d/15-lda.conf
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjusting file '15-lda.conf'.."
echo -e "$rc_not_yet_implemented"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/15-lda.conf
## -
## - postmaster_address = $postmaster_address
## - hostname = $hostname
## - sendmail_path = /usr/sbin/sendmail
## - lda_mailbox_autocreate = no
## - mail_plugins = $mail_plugins sieve
## -
echononl " Adjusting file '15-lda.conf'.."
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(postmaster_address\ +=.*)#\1\#\# \2\n\1postmaster_address = $postmaster_address#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-lda.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(hostname\ +=.*)#\1\#\# \2\n\1hostname = $hostname#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-lda.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(sendmail_path\ +=.*)#\1\#\# \2\n\1sendmail_path = /usr/sbin/sendmail#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-lda.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(lda_mailbox_autocreate\ +=.*)#\1\#\# \2\n\1lda_mailbox_autocreate = no#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-lda.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = \\\$mail_plugins sieve#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-lda.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting /usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-lda.conf failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/15-lda.conf
# edit /usr/local/dovecot/etc/dovecot/conf.d/20-lmtp
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjusting file '20-lmtp.conf'.."
echo -e "$rc_not_yet_implemented"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/20-lmtp
## -
## - lmtp_save_to_detail_mailbox = no
## - mail_plugins = $mail_plugins sieve
## -
echononl " Adjusting file '20-lmtp.conf'.."
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(lmtp_save_to_detail_mailbox\ +=.*)#\1\#\# \2\n\1lmtp_save_to_detail_mailbox = no#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-lmtp.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = \\\$mail_plugins sieve#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-lmtp.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting /usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-lmtp.conf failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/20-lmtp
# edit /usr/local/dovecot/etc/dovecot/conf.d/20-imap.conf
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjusting file '20-lmtp.conf'.."
echo -e "$rc_not_yet_implemented"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/20-imap.conf
## -
## - ssl_cert = <$imap_cert
## - ssl_key = <$imap_key
## - mail_max_userip_connections = $max_userip_connections
## - mail_plugins = $mail_plugins imap_quota
## - imap_client_workarounds = delay-newmail
## -
echononl " Adjusting file 20-imap.conf"
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(protocol imap \{)#\1\2\n\n\1 ssl_cert = <$imap_cert\n\1 ssl_key = <$imap_key\n#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-imap.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_max_userip_connections\ +=.*)#\1\#\# \2\n\1mail_max_userip_connections = $max_userip_connections#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-imap.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = \\\$mail_plugins imap_quota#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-imap.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(imap_client_workarounds\ +=.*)#\1\#\# \2\n\1imap_client_workarounds = delay-newmail#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-imap.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting /usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-imap.conf failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/20-imap.conf
# edit /usr/local/dovecot/etc/dovecot/conf.d/20-pop3.conf
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjusting file '20-pop3.conf'.."
echo -e "$rc_not_yet_implemented"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/20-pop3.conf
## -
## - ssl_cert = <$pop_cert
## - ssl_key = <$pop_key
## - mail_max_userip_connections = 24
## - pop3_client_workarounds = outlook-no-nuls oe-ns-eoh
## -
echononl " Adjusting file 20-pop3.conf"
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(protocol pop3 \{)#\1\2\n\n\1 ssl_cert = <$pop_cert\n\1 ssl_key = <$pop_key\n#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-pop3.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_max_userip_connections\ +=.*)#\1\#\# \2\n\1mail_max_userip_connections = 24#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-pop3.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(pop3_client_workarounds\ +=.*)#\1\#\# \2\n\1pop3_client_workarounds = outlook-no-nuls oe-ns-eoh#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-pop3.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting /usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-pop3.conf failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/20-pop3.conf
# edit /usr/local/dovecot/etc/dovecot/conf.d/90-plugin.conf
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjusting file '90-plugin.conf'.."
echo -e "$rc_skipped"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/90-plugin.conf
## -
## - Note:
## - Setting "autocreate", "autosubscribe" here is depricated. Use mailbox { auto } setting instead.
## -
## - expire = Trash
## - expire2 = Trash/*
## - expire3 = Spam
## -
## - expire_dict = proxy::expire
## -
## - # Enable caching of dict value in dovecot.index file. This significantly reduces
## - # the number of dict lookups. It makes initial testing more confusing though, so
## - # it's better to enable it only after you've verified that the expire plugin is
## - # working as wanted. (v2.2.16+)
## - expire_cache = yes
## -
echononl " Adjusting file 90-plugin.conf"
if $plugin_expire ; then
perl -i.ORIG -n -p -e "s#^([ ]*)(\#?\ ?setting_name\ +=.*)#\1\2\n\n\1expire = Trash\n\1expire2 = Trash/*\n\1expire3 = $spam_folder\n\n\1expire_dict = proxy::expire\n\n\1\# Enable caching of dict value in dovecot.index file. This significantly reduces\n\1\# the number of dict lookups. It makes initial testing more confusing though, so\n\1\# it's better to enable it only after you've verified that the expire plugin is\n\1\# working as wanted. (v2.2.16+)\n\1expire_cache = yes#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-plugin.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting /usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-plugin.conf failed"
fi
else
echo -e "$rc_skipped"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/90-plugin.conf
# edit /usr/local/dovecot/etc/dovecot/conf.d/90-sieve.conf
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjusting file '20-lmtp.conf'.."
echo -e "$rc_not_yet_implemented"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/90-sieve.conf
## -
## - sieve = ~/.dovecot.sieve
## - #sieve_global_path = /usr/local/dovecot/etc/dovecot/sieve/default.sieve
## - sieve_before = /usr/local/dovecot/etc/dovecot/sieve/move-spam.sieve
## - sieve_dir = ~/sieve
## - sieve_global = /usr/local/dovecot/etc/dovecot/sieve/global/
## - recipient_delimiter =
## -
echononl " Adjusting file 90-sieve.conf"
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(sieve\ ?=.*)#\1\#\# \2\n\1sieve = ~/.dovecot.sieve#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-sieve.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(sieve_before\ ?=.*)#\1\#\# \2\n\1sieve_before =/usr/local/dovecot/etc/dovecot/sieve/move-spam.sieve#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-sieve.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(sieve_dir\ ?=.*)#\1\#\# \2\n\1sieve_dir = ~/sieve#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-sieve.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(sieve_global\ ?=.*)#\1\#\# \2\n\1sieve_global = /usr/local/dovecot/etc/dovecot/sieve/global/#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-sieve.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(recipient_delimiter\ ?=.*)#\1\#\# \2\n\1recipient_delimiter =#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-sieve.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting /usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-sieve.conf"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/90-sieve.conf
# adjust /usr/local/dovecot/etc/dovecot/conf.d/90-sieve.conf
#
# Add Setting for included Pigeonhole Sieve: Vacation Extension
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Add Setting for included Pigeonhole Sieve: Vacation Extension'.."
echo -e "$rc_not_yet_implemented"
else
# - Add Setting from Pigeonhole Sieve: Vacation Extension
# -
echononl " Add Setting for included Pigeonhole Sieve: Vacation Extension"
_tmp_file="/tmp/dovecot_conf_90-sieve.conf"
cp -a "/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-sieve.conf" "$_tmp_file" > /dev/null 2>&1
:> $_tmp_file
while IFS='' read -r _line || [[ -n $_line ]] ; do
echo "$_line" >> "$_tmp_file"
if ! $_found && $(echo "$_line" | grep -i -E "^\s*plugin {" > /dev/null 2>&1) ; then
_found=true
cat <<EOF >> "$_tmp_file"
# Add Setting 'sieve_vacation_send_from_recipient' from (included)
#
# Pigeonhole Sieve: Vacation Extension
# ====================================
#
# sieve_vacation_send_from_recipient
#
# Default: no
#
# Values: Boolean
#
# This setting determines whether vacation messages are sent with the
# SMTP MAIL FROM envelope address set to the recipient address of the
# Sieve script owner.
#
# Normally this is set to <>, which is the default as recommended in the
# specification. This is meant to prevent mail loops. However, there are
# situations for which a valid sender address is required and this setting
# can be used to accommodate for those.
#
sieve_vacation_send_from_recipient = yes
EOF
fi
done < "/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-sieve.conf"
cp -a "$_tmp_file" "/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-sieve.conf" > /dev/null 2>&1
echo -e "$rc_done"
fi # adjust /usr/local/dovecot/etc/dovecot/conf.d/90-sieve.conf
echononl " Create Directory for global sieve scripts"
mkdir -p "/usr/local/dovecot-${_version}/etc/dovecot/sieve/global/" > $log_file 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "$(cat $log_file)"
echononl " continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
## - ceate global sieve script
## -
echononl " Ceate global sieve script"
cat <<EOF > /usr/local/dovecot-${_version}/etc/dovecot/sieve/move-spam.sieve
require ["fileinto"];
# rule:[Move Spam]
# Move spam to spam folder
if header :contains "X-Spam-Flag" ["YES"] {
fileinto "$spam_folder";
#discard;
stop;
}
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating global sieve script failed"
echononl " continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
## - NOTICE: if you pre-compile your (global) scripts, you will increase
## - performance
## -
echononl " Precompile global sieve script"
cd /usr/local/dovecot-${_version}/etc/dovecot/sieve/
/usr/local/dovecot-${_version}/bin/sievec \
/usr/local/dovecot-${_version}/etc/dovecot/sieve/move-spam.sieve > $log_file 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "$(cat $log_file)"
echononl " continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
## - you can also give dovecot's delivery service (lda / lmtp) the permissions to write
## - into the sieve directory. then dovecots delivery service will compile the script
## - by first using..
## -
chown -R vmail:vmail /usr/local/dovecot-${_version}/etc/dovecot/sieve
if $systemd_support; then
## - # - At time, we don't use private tmp directory for divecot.
## - # -
## - echononl " Adjust Systemd service file, set PrivateTmp=false.."
## - if [[ -f "/etc/systemd/system/dovecot.service" ]] ; then
## -
## - if $(grep -o -E "PrivateTmp\s*=\s*[^[:blank:]]+" /etc/systemd/system/dovecot.service | grep -q true 2> /dev/null ) ; then
## - perl -i -n -p -e "s/(PrivateTmp\s*=\s*)true/\1false/" /etc/systemd/system/dovecot.service
## - if [[ $? -eq 0 ]]; then
## - echo -e "$rc_done"
## - else
## - echo -e "$rc_failed"
## - fi
## - else
## - echo -e "$rc_skipped"
## - fi
## - else
## - echo -e "$rc_skipped"
## - fi
## - Increase LimitNOFILE to fit dovecots setting for 'default_client_limit'.
## -
## - here:
## - LimitNOFILE=32768
## -
if [[ -f "/lib/systemd/system/dovecot.service" ]] \
&& $(grep -q -E "^LimitNOFILE=" /lib/systemd/system/dovecot.service) ; then
_LimitNOFILE="$(grep -E "^LimitNOFILE=[[:digit:]]+" /lib/systemd/system/dovecot.service | cut -d'=' -f2)"
adjust_limit_nofile=false
if [[ $service_limit_nofile -gt _LimitNOFILE ]] ; then
adjust_limit_nofile=true
echononl " Create Directory '/etc/systemd/system/dovecot.service.d'.."
if [[ -d "/etc/systemd/system/dovecot.service.d" ]] ; then
echo -e "$rc_skipped"
else
mkdir "/etc/systemd/system/dovecot.service.d" > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
adjust_limit_nofile=false
fi
fi
fi
echononl " Adjust 'LimitNOFILE' for 'dovecot.service'.."
if ! $adjust_limit_nofile ; then
echo -e "$rc_skipped"
else
cat <<EOF > /etc/systemd/system/dovecot.service.d/set-limit-nofile.conf
[Service]
LimitNOFILE=$service_limit_nofile
EOF
echo -e "$rc_done"
fi
fi
echononl " Reload systemd .."
systemctl daemon-reload > /dev/null 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fi
## - Make dovecot start at boot time
## -
echononl " Make dovecot start at boottime.."
systemctl enable dovecot > /dev/null 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Make dovecot start at boottime (systend service) failed"
fi
else
## - Make dovecot start at boot time
## -
echononl " Make dovecot start at boottime.."
update-rc.d dovecot defaults > /dev/null 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Make dovecot start at boottime (init script) failed"
fi
fi
if $_new ; then
if ! $systemd_support; then
_create_init=""
echo
echo -n "Create init script /etc/init.d/dovecot ? [y/n]: "
read _create_init
if [ "y" = "$_create_init" -o "Y" = "$_create_init" -o "Yes" = "$_create_init" -o "yes" = "$_create_init" ];then
echononl " Create init script for dovecot .."
## - running dovecot service via init-script
## -
cat <<EOF > /etc/init.d/dovecot
#! /bin/sh
### BEGIN INIT INFO
# Provides: dovecot
# Required-Start: \$syslog \$postgresql
# Required-Stop: \$syslog \$postgresql
# Should-Start: \$local_fs \$time ntp
# Should-Stop: \$local_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Dovecot init script
# Description: Init script for dovecot services
### END INIT INFO
# Author: Miquel van Smoorenburg <miquels@cistron.nl>.
# Modified for Debian GNU/Linux
# by Ian Murdock <imurdock@gnu.ai.mit.edu>.
#
# Do NOT "set -e"
ulimit -n 32768
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/dovecot/sbin/dovecot:/usr/local/dovecot/bin
DESC="IMAP/POP3 mail server"
NAME=dovecot
DAEMON=/usr/local/dovecot/sbin/dovecot
DAEMON_ARGS=""
SCRIPTNAME=/etc/init.d/\$NAME
CONF=/usr/local/dovecot/etc/dovecot/\${NAME}.conf
# Read configuration variable file if it is present
[ -r /etc/default/\$NAME ] && . /etc/default/\$NAME
# Exit if the package is not installed
[ -x "\$DAEMON" ] || exit 0
# Exit if the configuration file doesn't exist
[ -f "\$CONF" ] || exit 0
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
# cong file readable?
if [ ! -r \${CONF} ]; then
[ "\$VERBOSE" != no ] && log_daemon_msg "\${CONF}: not readable" "\$NAME" \\
&& log_end_msg 1;
exit 1;
fi
# The init script should do nothing if dovecot or another imap/pop3 server
# is being run from inetd, and dovecot is configured to run as an imap or
# pop3 service
if [ -r /etc/inetd.conf ]; then
for p in \`sed -r "s/^ *(([^:]+|\[[^]]+]|\*):)?(pop3s?|imaps?)[ \t].*/\3/;t;d" \\
/etc/inetd.conf\`
do
for q in \`sed -r "s/^[ \t]*protocols[ \t]*=[ \t]*(([^\"]*)|\"(.*)\")/\2\3/;t;d" \\
\${CONF}\`
do
if [ \$p = \$q ]; then
exit 0
fi
done
done
fi
# determine the location of the PID file
# overide by setting base_dir in conf file or PIDBASE in /etc/defaults/\$NAME
PIDBASE=\${PIDBASE:-\`sed -r "s/^[ \t]*base_dir[ \t]*=[ \t]*([^ \t]*)/\1/;t;d" \${CONF}\`}
PIDFILE=\${PIDBASE:-/run/dovecot/}master.pid
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile \$PIDFILE --exec \$DAEMON --test > /dev/null \\
|| return 1
start-stop-daemon --start --quiet --pidfile \$PIDFILE --exec \$DAEMON -- \\
\$DAEMON_ARGS \\
|| return 2
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile \$PIDFILE --name \${DAEMON##*/}
RETVAL="\$?"
[ "\$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --pidfile \$PIDFILE --name \${DAEMON##*/}
[ "\$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f \$PIDFILE
return "\$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal USR1 --quiet --pidfile \$PIDFILE --name \$NAME
return 0
}
case "\$1" in
start)
[ "\$VERBOSE" != no ] && log_daemon_msg "Starting \$DESC" "\$NAME"
do_start
case "\$?" in
0|1) [ "\$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "\$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "\$VERBOSE" != no ] && log_daemon_msg "Stopping \$DESC" "\$NAME"
do_stop
case "\$?" in
0|1) [ "\$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "\$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
reload|force-reload)
log_daemon_msg "Reloading \$DESC" "\$NAME"
do_reload
log_end_msg \$?
;;
restart)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting \$DESC" "\$NAME"
do_stop
case "\$?" in
0|1)
do_start
case "\$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: \$SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: \$SCRIPTNAME {start|stop|restart|force-reload}" >&2
exit 3
;;
esac
exit 0
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Creating init script for dovecot failed"
fi
chmod 755 /etc/init.d/dovecot
else
echononl " Create init script for dovecot .."
echo -e "$rc_skipped"
fi
fi
## - Add a cronjob to restart dovecot after booting the system.
## -
## - Notice:
## - On normal start, dovecot started its service even if ipv6 is not
## - yet present and dovecot cannot bind to ipv6 listeners.
## -
## - Doimg a restart (after ipv6 adresses are present) fixes this.
## -
echononl " Create cronjob to restart dovecot service after reboot.."
_crontab_tmp_file=/tmp/crontab_root.$$
crontab -l > $_crontab_tmp_file 2> /dev/null
if [[ ! -s $_crontab_tmp_file ]]; then
echo "PATH=/usr/local/dovecot/bin:$PATH" > $_crontab_tmp_file
fi
if ! grep -q -E "\s*@reboot.*systemctl\s+restart\s+dovecot.service" $_crontab_tmp_file ; then
echo "" >> $_crontab_tmp_file
echo "# - Restart dovecot after reboot" >> $_crontab_tmp_file
echo "# -" >> $_crontab_tmp_file
echo "@reboot sleep 15 ; /bin/systemctl restart dovecot.service" >> $_crontab_tmp_file
crontab $_crontab_tmp_file
echo -e "$rc_done"
else
echo -e "$rc_skipped"
fi
rm -f $_crontab_tmp_file
## - update postfix configuration to play with dovecot lda
## -
## - /etc/postfix/master.cf
## -
## - add line
## - dovecot unix - n n - - pipe
## - flags=drhu user=vmail:vmail argv=/usr/local/dovecot/libexec/dovecot/dovecot-lda -f ${sender} -d ${user}@${nexthop}
if ! grep -e dovecot-lda /etc/postfix/master.cf > /dev/null ; then
cp -a "/etc/postfix/master.cf" "/etc/postfix/master.cf.$backup_date"
echononl " Configure /etc/postfix/master.cf to play with dovecot lda"
echo -e "\ndovecot unix - n n - - pipe\n flags=drhu user=vmail:vmail argv=/usr/local/dovecot/libexec/dovecot/dovecot-lda -f \${sender} -d \${user}@\${nexthop}" >> /etc/postfix/master.cf
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Configuring /etc/postfix/master.cf failed"
fi
fi
## - /etc/postfix/main.cf
## -
## - add/uncomment:
## -
## - smtpd_tls_auth_only
## -
## - smtpd_sasl_type = dovecot
## - smtpd_sasl_path = private/dovecot-auth
## -
## - virtual_transport = dovecot
## - dovecot_destination_recipient_limit = 1
## -
## - in section restrictions, parameter smtpd_recipient_restrictions
## - uncomment add
## -
## - permit_sasl_authenticated,
## -
_failed=false
echononl " Adjust /etc/postfix/main.cf"
perl -i.$backup_date -n -p -e "s#^(\s*)(smtpd_tls_auth_only\ *=.*)#smtpd_tls_auth_only = yes#" \
/etc/postfix/main.cf || _failed=true
perl -i -n -p -e "s#^(\s*)(smtpd_sasl_auth_enable\ *=.*)#smtpd_sasl_auth_enable = no#" \
/etc/postfix/main.cf || _failed=true
perl -i -n -p -e "s#^(\s*)(smtpd_sasl_type\ *=.*)#smtpd_sasl_type = dovecot#" \
/etc/postfix/main.cf || _failed=true
perl -i -n -p -e "s#^(\s*)(smtpd_sasl_path\ *=.*)#smtpd_sasl_path = private/dovecot-auth#" \
/etc/postfix/main.cf || _failed=true
perl -i -n -p -e "s#^(\s*)(virtual_transport\ *=.*)#virtual_transport = dovecot\ndovecot_destination_recipient_limit = 1#" \
/etc/postfix/main.cf || _failed=true
perl -i-n -p -e "s#^(\s*)\#?(permit_sasl_authenticated)#\1\2#" /etc/postfix/main.cf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting /etc/postfix/main.cf failed"
fi
## - add a cronjob to run expunge scripts, to delete old mails
## - from users'mailbox. only cleanup spam and trash directories
## -
echononl " Create cronjob to run expunge scripts"
_crontab_tmp_file=/tmp/crontab_root.$$
crontab -l > $_crontab_tmp_file 2> /dev/null
if [[ ! -s $_crontab_tmp_file ]]; then
echo "PATH=/usr/local/dovecot/bin:$PATH" > $_crontab_tmp_file
fi
if ! grep -e "/usr/local/dovecot/bin/doveadm\ *expunge" $_crontab_tmp_file > /dev/null ; then
echo "" >> $_crontab_tmp_file
echo "# - cleanup spam and trash directories of users'mailboxes" >> $_crontab_tmp_file
echo "# -" >> $_crontab_tmp_file
echo "13 3 * * * /usr/local/dovecot/bin/doveadm expunge -A mailbox Trash* savedbefore 3d; /usr/local/dovecot/bin/doveadm expunge -A mailbox ${spam_folder}* savedbefore 30d" >> $_crontab_tmp_file
crontab $_crontab_tmp_file
echo -e "$rc_done"
else
echo -e "$rc_skipped"
fi
rm -f $_crontab_tmp_file
fi # if $_new
echo
echo -e "\033[1mChange (from lda) to lmtp-service\033[m"
## -----------------
## --- Change (from lda) to lmtp-service
## - edit /usr/local/dovecot/etc/dovecot/dovecot.conf
## -
## - add "lmtp" to protocols
## -
_failed=false
echononl " Add lmtp to protocols (dovecot.conf)"
perl -i -n -p -e "s#^([ ]*)(protocols\ +=\ +.*)#\1\2 lmtp#" \
/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adding lmtp to protocols in file /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf failed"
fi
## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-master.conf
## -
## - unix_listener /var/spool/postfix/private/dovecot-lmtp {
## - mode = 0600
## - user = postfix
## - group = postfix
## - }
## -
echononl " Adding dovecot-lmtp listener to 10-master.conf"
perl -i -n -p -e "s#^([ ]*)(unix_listener\ +lmtp\ .*)#\1unix_listener /var/spool/postfix/private/dovecot-lmtp {\n user = postfix\n mode = 0660\n group = postfix#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf failed"
fi
# - /etc/postfix/main.cf
# -
# - comment in:
# - #virtual_transport = dovecot
# - #dovecot_destination_recipient_limit = ..
# -
# - change:
# - smtpd_sasl_auth_enable = yes
# - smtpd_sasl_type = dovecot
# - smtpd_sasl_path = private/dovecot-auth
# - virtual_transport = lmtp:unix:private/dovecot-lmtp
var="smtpd_sasl_auth_enable"
val="yes"
echononl " ${postfix_main_cf}: adjust '${var}'.."
if ! $(grep -E -q "^\s*${var}\s*=\s*${val}" ${postfix_main_cf} 2> /dev/null) ; then
perl -i -n -p -e "s#^(\s*)(${var}\ *=.*)#${var} = ${val}#" \
/etc/postfix/main.cf > $log_file 2>&1
if [[ $? -eq 0 ]]; then
echo_ok
changed=true
else
echo_failed
error "$(cat "$log_file")"
fi
else
echo_skipped
fi
var="smtpd_sasl_type"
val="dovecot"
echononl " ${postfix_main_cf}: adjust '${var}'.."
if ! $(grep -E -q "^\s*${var}\s*=\s*${val}" ${postfix_main_cf} 2> /dev/null) ; then
perl -i -n -p -e "s#^(\s*)(${var}\ *=.*)#${var} = ${val}#" \
/etc/postfix/main.cf > $log_file 2>&1
if [[ $? -eq 0 ]]; then
echo_ok
changed=true
else
echo_failed
error "$(cat "$log_file")"
fi
else
echo_skipped
fi
var="smtpd_sasl_path"
val="private/dovecot-auth"
echononl " ${postfix_main_cf}: adjust '${var}'.."
if ! $(grep -E -q "^\s*${var}\s*=\s*${val}" ${postfix_main_cf} 2> /dev/null) ; then
perl -i -n -p -e "s#^(\s*)(${var}\ *=.*)#${var} = ${val}#" \
/etc/postfix/main.cf > $log_file 2>&1
if [[ $? -eq 0 ]]; then
echo_ok
changed=true
else
echo_failed
error "$(cat "$log_file")"
fi
else
echo_skipped
fi
var="virtual_transport"
val="lmtp:unix:private/dovecot-lmtp"
echononl " ${postfix_main_cf}: adjust '${var}'.."
if ! $(grep -E -q "^\s*${var}\s*=\s*${val}" ${postfix_main_cf} 2> /dev/null) ; then
perl -i -n -p -e "s#^(\s*)(${var}\ *=.*)#${var} = ${val}#" \
/etc/postfix/main.cf > $log_file 2>&1
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
changed=true
error "$(cat "$log_file")"
fi
else
echo_skipped
fi
echononl " Comment variable 'dovecot_destination_recipient_limit'.."
if $(grep -E -q "^\s*dovecot_destination_recipient_limit" ${postfix_main_cf} 2> /dev/null) ; then
perl -i-n -p -e "s/^(\s*)(dovecot_destination_recipient_limit.*)/\1\#\2/" /etc/postfix/main.cf > $log_file 2>&1
if [[ $? -eq 0 ]]; then
echo_ok
changed=true
else
echo_failed
error "$(cat "$log_file")"
fi
else
echo_skipped
fi
## -----------------
## --- Configure quota support for dovecot
echo
echo -e "\033[1mConfigure quota support for dovecot\033[m"
## - take care quota plugins (quota,imap_quota) will
## - be loaded:
## -
## - there are two quota related plugins:
## -
## - * quota: implements the actual quota handling and includes also all the quota backends.
## - * imap_quota: for reporting quota information via imap.
## -
## - enable them in configuration files, e.g.:
## -
## - conf.d/10-mail.conf:
## -
## - # space separated list of plugins to load for all services. plugins specific to
## - # imap, lda, etc. are added to this list in their own .conf files.
## - mail_plugins = $mail_plugins quota
## -
## - conf.d/20-imap.conf:
## -
## - protocol imap {
## - # space separated list of plugins to load (default is global mail_plugins).
## - mail_plugins = $mail_plugins imap_quota
## - }
## -
## - we have done it befor, at the basic configuration
## -
## - configure dict service
## -
## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-master.conf
## -
## - add:
## -
## - service dict {
## - unix_listener dict {
## - mode = 0600
## - user = vmail
## - }
## - }
## -
_failed=false
echononl " Configure dict service (10-master.conf)"
perl -i -n -p -e "s#^([ ]*)(unix_listener\ +dict.*)#\1\2\n\1 mode = 0600\n\1 user = vmail#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf failed"
fi
## - edit /usr/local/dovecot/etc/dovecot/dovecot.conf
## -
## - add:
## -
## - dict {
## - quota = $db_driver:/usr/local/dovecot/etc/dovecot/sql-dict.conf.ext
## - }
_failed=false
echononl " Adjust file dovecot.conf for (dict) quota service"
perl -i -n -p -e "s#^([ ]*)(dict\ +{.*)#\1\2\n\1 quota = $db_driver:/usr/local/dovecot/etc/dovecot/sql-dict.conf.ext#g" \
/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf failed"
fi
if $_new ; then
if [ "$db_driver" = "pgsql" ]; then
echononl " Create table quota2 in database \"$dbname\".."
cat << EOF | psql -U$dbuser $dbname > /dev/null 2>&1
CREATE TABLE IF NOT EXISTS quota2 (
username varchar(100) not null,
bytes bigint not null default 0,
messages integer not null default 0,
primary key (username)
);
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating table quota2 in database \"$dbname\" failed"
fi
echononl " Create Trigger mergequota2.."
cat << EOF | psql -U$dbuser $dbname > /dev/null 2>&1
CREATE PROCEDURAL LANGUAGE plpgsql;
CREATE FUNCTION merge_quota2() RETURNS trigger
LANGUAGE plpgsql
AS \$\$
BEGIN
IF NEW.messages < 0 OR NEW.messages IS NULL THEN
-- ugly kludge: we came here from this function, really do try to insert
IF NEW.messages IS NULL THEN
NEW.messages = 0;
ELSE
NEW.messages = -NEW.messages;
END IF;
return NEW;
END IF;
LOOP
UPDATE quota2 SET bytes = bytes + NEW.bytes,
messages = messages + NEW.messages
WHERE username = NEW.username;
IF found THEN
RETURN NULL;
END IF;
BEGIN
IF NEW.messages = 0 THEN
INSERT INTO quota2 (bytes, messages, username) VALUES (NEW.bytes, NULL, NEW.username);
ELSE
INSERT INTO quota2 (bytes, messages, username) VALUES (NEW.bytes, -NEW.messages, NEW.username);
END IF;
return NULL;
EXCEPTION WHEN unique_violation THEN
-- someone just inserted the record, update it
END;
END LOOP;
END;
\$\$;
CREATE TRIGGER mergequota2
BEFORE INSERT ON quota2
FOR EACH ROW
EXECUTE PROCEDURE merge_quota2();
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Creating function merge_quota2() / trigger merge_quota2 failed"
fi
elif [ "$db_driver" = "mysql" ]; then
echononl " Create table quota2 in database \"$dbname\".."
cat << EOF | mysql -u$dbuser -p$dbpassword $dbname > /dev/null 2>&1
CREATE TABLE IF NOT EXISTS quota2 (
username varchar(100) not null,
bytes bigint not null default 0,
messages integer not null default 0,
primary key (username)
);
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating table quota2 in database \"$dbname\" failed"
fi
fi
fi
_failed=false
echononl " Renew file sql-dict.conf.ext"
if [ "$db_driver" = "pgsql" ]; then
cat <<EOF >/usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
## - if using unix-socket (host=/run/postgresql) ensure that
## - coresponding entries in pg_hba.cof fits
## - for example
## - local all all md5
## -
connect = host=$dbhost user=$dbuser password=$dbpassword dbname=$dbname
# CREATE TABLE quota2 (
# username varchar(100) not null,
# bytes bigint not null default 0,
# messages integer not null default 0,
# primary key (username)
# );
#
## - if using postgres, you need also to create a trigger as follows:
## -
## - first create language plpgsql if not yet created:
## -
# CREATE PROCEDURAL LANGUAGE plpgsql;
#
# CREATE FUNCTION merge_quota2() RETURNS trigger
# LANGUAGE plpgsql
# AS \$\$
# BEGIN
# IF NEW.messages < 0 OR NEW.messages IS NULL THEN
# -- ugly kludge: we came here from this function, really do try to insert
# IF NEW.messages IS NULL THEN
# NEW.messages = 0;
# ELSE
# NEW.messages = -NEW.messages;
# END IF;
# return NEW;
# END IF;
#
# LOOP
# UPDATE quota2 SET bytes = bytes + NEW.bytes,
# messages = messages + NEW.messages
# WHERE username = NEW.username;
# IF found THEN
# RETURN NULL;
# END IF;
#
# BEGIN
# IF NEW.messages = 0 THEN
# INSERT INTO quota2 (bytes, messages, username) VALUES (NEW.bytes, NULL, NEW.username);
# ELSE
# INSERT INTO quota2 (bytes, messages, username) VALUES (NEW.bytes, -NEW.messages, NEW.username);
# END IF;
# return NULL;
# EXCEPTION WHEN unique_violation THEN
# -- someone just inserted the record, update it
# END;
# END LOOP;
# END;
# \$\$;
#
#
# ALTER FUNCTION public.merge_quota2() OWNER TO postfix;
#
# CREATE TRIGGER mergequota2
# BEFORE INSERT ON quota2
# FOR EACH ROW
# EXECUTE PROCEDURE merge_quota2();
map {
pattern = priv/quota/storage
table = quota2
username_field = username
value_field = bytes
}
map {
pattern = priv/quota/messages
table = quota2
username_field = username
value_field = messages
}
EOF
if [[ "$?" -gt 0 ]]; then
_failed=true
fi
if $plugin_expire ; then
cat <<EOF >> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
# CREATE TABLE expires (
# username varchar(100) not null,
# mailbox varchar(255) not null,
# expire_stamp integer not null,
# primary key (username, mailbox)
# );
## - if using postgres, you need also to create a trigger as follows:
## -
## - first create language plpgsql if not yet created:
## -
# CREATE LANGUAGE plpgsql;
#
# CREATE OR REPLACE FUNCTION merge_expires() RETURNS TRIGGER AS \$\$
# BEGIN
# UPDATE expires SET expire_stamp = NEW.expire_stamp
# WHERE username = NEW.username AND mailbox = NEW.mailbox;
# IF FOUND THEN
# RETURN NULL;
# ELSE
# RETURN NEW;
# END IF;
# END;
# \$\$ LANGUAGE plpgsql;
#
# CREATE TRIGGER mergeexpires BEFORE INSERT ON expires
# FOR EACH ROW EXECUTE PROCEDURE merge_expires();
map {
pattern = shared/expire/\$user/\$mailbox
table = expires
value_field = expire_stamp
fields {
username = \$user
mailbox = \$mailbox
}
}
EOF
if [[ "$?" -gt 0 ]]; then
_failed=true
fi
fi
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Recreating file /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext failed"
fi
## - you also have to update the userdb's query in file
## - "/usr/local/dovecot/etc/dovecot/sql-connect.conf.ext" to
## - support extra variable "quota_rule"
## -
echononl " Renew file sql-connect.conf.ext"
cat <<EOF > /usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf.ext
driver = $db_driver
## - if using unix-socket (host=/run/postgresql) ensure that
## - coresponding entries in pg_hba.cof fits
## - for example
## - local all all md5
## -
connect = host=$dbhost user=$dbuser password=$dbpassword dbname=$dbname
default_pass_scheme = $default_pass_scheme
password_query = SELECT username AS user, password \\
FROM mailbox \\
WHERE username = '%u' AND active = true
user_query = SELECT '/var/vmail/' || maildir AS home, \\
'5000' AS uid, '5000' AS gid, \\
'*:bytes=' || quota AS quota_rule \\
FROM mailbox \\
WHERE username = '%u' AND active = true
## - Query to get a list of all usernames.
## -
iterate_query = SELECT username AS user FROM mailbox
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Recreating file /usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf.ext failed"
fi
elif [ "$db_driver" = "mysql" ]; then
cat <<EOF >/usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
connect = host=$dbhost user=$dbuser password=$dbpassword dbname=$dbname
# CREATE TABLE quota2 (
# username varchar(100) not null,
# bytes bigint not null default 0,
# messages integer not null default 0,
# primary key (username)
# );
map {
pattern = priv/quota/storage
table = quota2
username_field = username
value_field = bytes
}
map {
pattern = priv/quota/messages
table = quota2
username_field = username
value_field = messages
}
EOF
if [[ "$?" -gt 0 ]]; then
_failed=true
fi
if $plugin_expire ; then
cat <<EOF >> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
# CREATE TABLE expires (
# username varchar(100) not null,
# mailbox varchar(255) not null,
# expire_stamp integer not null,
# primary key (username, mailbox)
# );
map {
pattern = shared/expire/\$user/\$mailbox
table = expires
value_field = expire_stamp
fields {
username = \$user
mailbox = \$mailbox
}
}
EOF
if [[ "$?" -gt 0 ]]; then
_failed=true
fi
fi
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Recreating file /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext failed"
fi
## - you also have to update the userdb's query in file
## - "/usr/local/dovecot/etc/dovecot/sql-connect.conf.ext" to
## - support extra variable "quota_rule"
## -
echononl " Renew file sql-connect.conf.ext"
cat <<EOF > /usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf.ext
driver = $db_driver
connect = host=$dbhost user=$dbuser password=$dbpassword dbname=$dbname
default_pass_scheme = $default_pass_scheme
password_query = SELECT username AS user, password \\
FROM mailbox \\
WHERE username = '%u' AND active = true
user_query = SELECT CONCAT('/var/vmail/',maildir) AS home, \\
'5000' AS uid, '5000' AS gid, \\
CONCAT('*:bytes=',quota) AS quota_rule \\
FROM mailbox \\
WHERE username = '%u' AND active = true
## - Query to get a list of all usernames.
## -
iterate_query = SELECT username AS user FROM mailbox
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Recreating file /usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf.ext failed"
fi
fi
## - configure stats service (10-master.conf)
## -
echononl " Configure stats service (10-master.conf)"
cat <<EOF >> /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf
service stats {
fifo_listener stats-mail {
user = vmail
group = dovecot
mode = 0660
}
unix_listener stats-reader {
user = vmail
group = dovecot
mode = 0660
}
unix_listener stats-writer {
user = vmail
group = dovecot
mode = 0660
}
}
EOF
if [[ $? -gt 0 ]] ; then
echo -e "$rc_failed"
error "Configure stats service (10-master.conf) failed!"
else
echo -e "$rc_done"
fi
## - configure post-login service (10-master.conf)
## -
## - see also: https://wiki.dovecot.org/PostLoginScripting
## -
echononl " Add script '/usr/local/dovecot-${_version}/bin/post-login.sh'.."
cat <<EOF > /usr/local/dovecot-${_version}/bin/post-login.sh
#!/usr/bin/env bash
touch ~/.last_login
exec "\$@"
EOF
if [[ $? -gt 0 ]] ; then
echo -e "$rc_failed"
error "Adding script '/usr/local/dovecot-${_version}/bin/post-login.sh' failed!"
else
echo -e "$rc_done"
fi
echononl " Set Permissions of 'post-login.sh' .."
chmod 755 "/usr/local/dovecot-${_version}/bin/post-login.sh" > /dev/null 2>&1
if [[ $? -gt 0 ]] ; then
echo -e "$rc_failed"
error "Setting permissions to '/usr/local/dovecot-${_version}/bin/post-login.sh' failed!"
else
echo -e "$rc_done"
fi
# Configure post-login service (10-master.conf)
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Configure post-login service (10-master.conf).."
_master_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf"
_service_imap_block="service imap {\n # tell imap to do post-login lookup using a socket called \"imap-postlogin\"\n executable = imap post-login\n}"
_service_pop3_block="service pop3 {\n # tell pop3 to do post-login lookup using a socket called \"pop3-postlogin\"\n executable = imap post-login\n}"
if grep -qE '^\s*service\s+imap\s*{' "${_master_conf_file}"; then
sed -i "/^\s*service\s+imap\s*{/,/^}/c\
${_service_imap_block}" ${_master_conf_file} || _failed=true
else
cat <<EOF >> "${_master_conf_file}" || _failed=true
$(echo -e "${_service_imap_block}")
EOF
fi
if grep -qE '^\s*service\s+pop3\s*{' "${_master_conf_file}"; then
sed -i "/^\s*service\s+pop3\s*{/,/^}/c\
${_service_pop3_block}" ${_master_conf_file} || _failed=true
else
cat <<EOF >> "${_master_conf_file}" || _failed=true
$(echo -e "${_service_pop3_block}")
EOF
fi
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Configure post-login service (10-master.conf) failed"
echo ""
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Interupted by user"
fi
else
echononl " Configure post-login service (10-master.conf)"
perl -i -n -p -e "s#^(\s*)(service\s+imap\s+{.*)#\1\2\n\1 \# tell imap to do post-login lookup using a socket called \"imap-postlogin\"\n\1 executable = imap post-login\n#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
perl -i -n -p -e "s#^(\s*)(service\s+pop3\s+{.*)#\1\2\n\1 \# tell imap to do post-login lookup using a socket called \"imap-postlogin\"\n\1 executable = pop3 post-login\n#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true
cat <<EOF >> /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf
service post-login {
# all post-login scripts are executed via script-login binary
executable = script-login /usr/local/dovecot/bin/post-login.sh
# the script process runs as the user specified here:
user = vmail
# this UNIX socket listener must use the same name as given to imap executable
unix_listener post-login {
}
}
EOF
if [[ $? -gt 0 ]] ; then
_failed=true
fi
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Configuring 'post-login' service failed!"
fi
fi # Configure post-login service (10-master.conf)
# edit /usr/local/dovecot/etc/dovecot/conf.d/90-quota.conf
#
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjust file '90-quota.conf'.."
echo -e "$rc_skipped"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/90-quota.conf
## -
## - add to the end of file or in seperate plugin-blocks
## - as designed in that file:
## - plugin {
## - # sql backend:
## - quota = dict:user quota::proxy::quota
## -
## - quota_rule = *:storage=1g
## - quota_rule2 = trash:storage=+100m
## -
## - quota_warning = storage=80%% quota-warning 80 %u
## - quota_warning2 = storage=95%% quota-warning 95 %u
## - }
## -
## - service quota-warning {
## - executable = script /usr/local/bin/quota-warning.sh
## - user = vmail
## - unix_listener quota-warning {
## - user = vmail
## - mode = 0666
## - }
## - }
## -
echononl " Adjust file 90-quota.conf"
cp -a /usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-quota.conf \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-quota.conf.ORIG
cat <<EOF >>/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-quota.conf
## -
plugin {
# SQL backend:
quota = dict:User quota::proxy::quota
quota_rule = *:storage=1G
quota_rule2 = Trash:storage=+200M
quota_warning = storage=80%% quota-warning 80 %u
quota_warning2 = storage=95%% quota-warning 95 %u
}
service quota-warning {
executable = script /usr/local/bin/quota-warning.sh
user = vmail
unix_listener quota-warning {
user = vmail
mode = 0666
}
}
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-quota.conf failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/90-quota.conf
if $_new ; then
echononl " Create quota warning script.."
## - create the user-warning script
## -
cat <<EOF >/usr/local/bin/quota-warning.sh
#!/usr/bin/env bash
# author: zhang huangbin <michaelbibby (at) gmail.com>
# purpose: send mail to notify user when his mailbox quota exceeds a
# specified limit.
# project: iredmail (http://www.iredmail.org/)
LANG=en_US.UTF-8
percent=\$1
user=\$2
cat << EOF | /usr/local/dovecot/libexec/dovecot/deliver -d \${user} -c /usr/local/dovecot/etc/dovecot/dovecot.conf -o "plugin/quota=dict:User quota::noenforcing:proxy::quota"
date: \`date +"%a, %e %b %Y %H:%M:%S %z"\`
from: $from_address
reply-to: $reply_to
to:\${user}
subject: mailbox quota warning: \${percent}% belegt.
content-type: text/plain;
charset=utf-8
Hallo!
Deine Mailbox für das Postfach
\${user}
ist nun zu über \${percent}% voll. Damit Du weiterhin E-Mails
empfangen kannst, lösche bitte vorhandene E-Mails vom Server.
Dies geht zum Beispiel via Webmailer:
$webmailer
Viele Grüße
$salutation
${_EOF:-EOF}
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Create quota warning script /usr/local/bin/quota-warning.sh failed"
fi
chmod 755 /usr/local/bin/quota-warning.sh
fi
## -----------------
## --- Configure ACL support for dovecot
## - What to do:
## -
## - 1.) Add shared namespace
## - 2.) Add plugins to the several plugin lists
## - - "acl" to variable mail_plugins in 10-mail.conf
## - - "acl-imap" to variable mail_plugins in 20-imap.conf
## -
## - 3.a) Add acl to the plugin part in 90-acl.conf
## -
## - 3.b) To make shared mailboxes visible a database (dict) is needed.
## - This can also be a dict file.
## - Add acl_shared_dict to the plugin part of 90-acl.conf
## -
## - 4.) If using SQL backend, also a rule "acl =" in "dict" section
## - of file dovecont.conf needed
## -
## edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
##
## Add namespaces type shared to 10-mail.conf
##
#if [[ $dovecot_major_version -gt 2 ]] \
# || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
#
# echononl " Add namespaces type shared to '10-mail.conf'...."
# echo -e "$rc_not_yet_implemented"
#
#else
#
# ## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
# ## -
# ## - Add namespaces type shared to 10-mail.conf
# ## - Take care to enable ACL plugin also, otherwise all users can access all the shared
# ## - mailboxes, assuming they have permissions on filesystem level to do so.
# ## - we will do that later..
# ## - namespace {
# ## - type = shared
# ## - separator = /
# ## - prefix = shared/%%u/
# ## - location = maildir:/var/vmail/%%d/%%n/Maildir:INDEX=~/Maildir/shared/%%u
# ## - subscriptions = no
# ## - list = children
# ## - }
# ## -
# echononl " Add namespaces type shared to 10-mail.conf"
# cat <<EOF >> /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf
#
#namespace {
# #type = shared
# #separator = /
# type = shared
# separator = /
#
# # Mailboxes are visible under "shared/user@domain/"
# # %%n, %%d and %%u are expanded to the destination user.
# #prefix = shared/%%u/
# prefix = shared/%%u/
#
# # Mail location for other users' mailboxes. Note that %variables and ~/
# # expands to the logged in user's data. %%n, %%d, %%u and %%h expand to the
# # destination user's data.
# #location = maildir:%%h/Maildir:INDEX=~/Maildir/shared/%%u
# location = maildir:/var/vmail/%%d/%%n/Maildir:INDEX=~/Maildir/shared/%%u
#
# # Use the default namespace for saving subscriptions.
# subscriptions = no
#
# # List the shared/ namespace only if there are visible shared mailboxes.
# list = children
#}
#EOF
# if [ "$?" = 0 ]; then
# echo -e "$rc_done"
# else
# echo -e "$rc_failed"
# fatal "Adding namespaces to /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf failed"
# fi
#
#fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
# edit /usr/local/dovecot/etc/dovecot/conf.d/20-imap.conf
#
# mail_plugins = $mail_plugins imap_quota imap_acl
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Add mail_plugin imap_acl to '20-imap.conf'.."
echo -e "$rc_not_yet_implemented"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/20-imap.conf
## -
## - mail_plugins = $mail_plugins imap_quota imap_acl
## -
echononl " Add mail_plugin imap_acl to 20-imap.conf"
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = \\\$mail_plugins imap_quota imap_acl#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-imap.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-imap.conf failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/20-imap.conf
## edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
##
#_failed=false
#_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf"
#if [[ $dovecot_major_version -gt 2 ]] \
# || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
#
# echononl " Adjust the mail_plugins parameter in the $(basename "${_conf_file}") file.."
# echo -e "$rc_not_yet_implemented"
#
#else
#
# ## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
# ## -
# ## - mail_plugins = quota expire acl
# ## -
# _failed=false
# echononl " Adjust the mail_plugins parameter in the $(basename "${_conf_file}") file.."
#
# if $plugin_expire ; then
# perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota expire acl#g" \
# /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
# else
# perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota acl#g" \
# /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true
# fi
#
# if ! $_failed ; then
# echo -e "$rc_done"
# else
# echo -e "$rc_failed"
# fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf failed"
# fi
#
#fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf
## - !! Notice !!
## - There a two possibilities, configuring acl backend:
## - - flat file
## - - SQL dictionary
## -
## - On rage.so36.net we actually uses SQL dictionary not a flat file
## -----------------
## - Using a flat file as dictionary backend
## -
## - edit /usr/local/dovecot/etc/dovecot/conf.d/90-acl.conf
## -
## - plugin {
## - # Without global ACLs:
## - acl = vfile
## -
## - # With global ACLs in /etc/dovecot/acls/ directory:
## - #acl = vfile:/etc/dovecot/acls
## - #acl = vfile:/etc/dovecot/acls:cache_secs=300
## - }
## -
## - plugin {
## - #acl_shared_dict = file:/run/dovecot/shared-mailboxes.db
## - acl_shared_dict = file:/var/vmail/shared-mailboxes.db
## - }
## -
#perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(acl\ +=.*)#\1\#\# \2\n\n\1\# Without global ACLs:\n\1acl = vfile\n\n\1\# With global ACLs in /etc/dovecot/acls/ directory:\n\1\#acl = vfile:/etc/dovecot/acls\n\1\#acl = vfile:/etc/dovecot/acls:cache_secs=300#g" \
# /usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-acl.conf
#perl -i -n -p -e "s#^([ ]*)\#?\ ?(acl_shared_dict\ +=.*)#\1\#\# \2\n\1acl_shared_dict = file:/var/vmail/shared-mailboxes.db#g" \
# /usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-acl.conf
## -
## - End: Using a flat file as dictionary backend
## ------------------------------------------------------------------------
## ------------------------------------------------------------------------
## - Using SQL dictionary
## -
# edit /usr/local/dovecot/etc/dovecot/conf.d/90-acl.conf
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Configure acl - file '90-acl.conf'.."
echo -e "$rc_not_yet_implemented"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/90-acl.conf
## -
## - plugin {
## - ## acl = vfile:/etc/dovecot/global-acls:cache_secs=300
## -
## - # Without global ACLs:
## - acl = vfile
## - ..
## - }
## - plugin {
## - acl_shared_dict = proxy::acl
## - }
## -
_failed=false
echononl " Configure acl (90-acl.conf)"
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(acl\ +=.*)#\1\#\# \2\n\n\1\# Without global ACLs:\n\1acl = vfile\n\n\1\# With global ACLs in /etc/dovecot/acls/ directory:\n\1\#acl = vfile:/etc/dovecot/acls\n\1\#acl = vfile:/etc/dovecot/acls:cache_secs=300#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-acl.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(acl_shared_dict\ +=.*)#\1\#\# \2\n\1acl_shared_dict = proxy::acl#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-acl.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-acl.conf failed"
fi
## - edit /usr/local/dovecot/etc/dovecot/dovecot.conf
## -
## - dict {
## - acl = $db_driver:/usr/local/dovecot/etc/dovecot/sql-dict.conf.ext
## - ...
## - }
## -
_failed=false
echononl " Adjust file dovecot.conf for (dict) acl service"
perl -i -n -p -e "s#^([ ]*)(dict\ +{.*)#\1\2\n\1 acl = $db_driver:/usr/local/dovecot/etc/dovecot/sql-dict.conf.ext#g" \
/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/90-acl.conf
if $_new ; then
if [ "$db_driver" = "pgsql" ]; then
## - Create tables user_shares / anyone_shares
## -
echononl " Create table user_share"
cat << EOF | psql -U$dbuser $dbname > /dev/null 2>&1
CREATE TABLE IF NOT EXISTS user_shares (
from_user varchar(100) not null,
to_user varchar(100) not null,
dummy char(1) DEFAULT '1', -- always '1' currently
primary key (from_user, to_user)
);
COMMENT ON TABLE user_shares IS 'User from_user shares folders to user to_user.';
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating table user_shares failed"
fi
echononl " Create table anyone_shares"
cat << EOF | psql -U$dbuser $dbname > /dev/null 2>&1
CREATE TABLE IF NOT EXISTS anyone_shares (
from_user varchar(100) not null,
dummy char(1) DEFAULT '1', -- always '1' currently
primary key (from_user)
);
COMMENT ON TABLE anyone_shares IS 'User from_user shares folders to anyone.';
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating table anyone_shares failed"
fi
elif [ "$db_driver" = "mysql" ]; then
## - Create table user_shares / anyone_shares
## -
echononl " Create table user_share"
cat << EOF | mysql -u$dbuser -p$dbpassword $dbname > /dev/null 2>&1
CREATE TABLE IF NOT EXISTS user_shares (
from_user varchar(100) not null,
to_user varchar(100) not null,
dummy char(1) DEFAULT '1', -- always '1' currently
primary key (from_user, to_user)
) COMMENT = 'User from_user shares folders to user to_user.';
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating table user_shares failed"
fi
echononl " Create table anyone_shares"
cat << EOF | mysql -u$dbuser -p$dbpassword $dbname > /dev/null 2>&1
CREATE TABLE IF NOT EXISTS anyone_shares (
from_user varchar(100) not null,
dummy char(1) DEFAULT '1', -- always '1' currently
primary key (from_user)
) COMMENT = 'User from_user shares folders to anyone.';
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating table anyone_shares failed"
fi
fi
fi
_failed=false
echononl " Renew file sql-dict.conf.ext"
if [ "$db_driver" = "pgsql" ]; then
## - adjust/renew file /usr/local/dovecot/etc/dovecot/sql-dict.conf.ext
## -
cat <<EOF >/usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
## - if using unix-socket (host=/run/postgresql) ensure that
## - coresponding entries in pg_hba.cof fits
## - for example
## - local all all md5
## -
connect = host=$dbhost user=$dbuser password=$dbpassword dbname=$dbname
## - NOTE:
## -
## - All changes on database (CREATE TABLE / CREATE TRIGGER / what else..)
## - need to be done as the dbuser (here postfix) under whom dovecot
## - accesses the database. If not, you have to change the permissiond to allow
## - dovecot dbuser to access the createt table/trigger/...
## -
# CREATE TABLE quota2 (
# username varchar(100) not null,
# bytes bigint not null default 0,
# messages integer not null default 0,
# primary key (username)
# );
#
## - if using postgres, you need also to create a trigger as follows:
## -
## - first create language plpgsql if not yet created:
## -
# CREATE PROCEDURAL LANGUAGE plpgsql;
#
# CREATE FUNCTION merge_quota2() RETURNS trigger
# LANGUAGE plpgsql
# AS \$\$
# BEGIN
# IF NEW.messages < 0 OR NEW.messages IS NULL THEN
# -- ugly kludge: we came here from this function, really do try to insert
# IF NEW.messages IS NULL THEN
# NEW.messages = 0;
# ELSE
# NEW.messages = -NEW.messages;
# END IF;
# return NEW;
# END IF;
#
# LOOP
# UPDATE quota2 SET bytes = bytes + NEW.bytes,
# messages = messages + NEW.messages
# WHERE username = NEW.username;
# IF found THEN
# RETURN NULL;
# END IF;
#
# BEGIN
# IF NEW.messages = 0 THEN
# INSERT INTO quota2 (bytes, messages, username) VALUES (NEW.bytes, NULL, NEW.username);
# ELSE
# INSERT INTO quota2 (bytes, messages, username) VALUES (NEW.bytes, -NEW.messages, NEW.username);
# END IF;
# return NULL;
# EXCEPTION WHEN unique_violation THEN
# -- someone just inserted the record, update it
# END;
# END LOOP;
# END;
# \$\$;
#
#
# ALTER FUNCTION public.merge_quota2() OWNER TO postfix;
#
# CREATE TRIGGER mergequota2
# BEFORE INSERT ON quota2
# FOR EACH ROW
# EXECUTE PROCEDURE merge_quota2();
map {
pattern = priv/quota/storage
table = quota2
username_field = username
value_field = bytes
}
map {
pattern = priv/quota/messages
table = quota2
username_field = username
value_field = messages
}
EOF
if [[ "$?" -gt 0 ]]; then
_failed=true
fi
if $plugin_expire ; then
cat <<EOF >> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
# CREATE TABLE expires (
# username varchar(100) not null,
# mailbox varchar(255) not null,
# expire_stamp integer not null,
# primary key (username, mailbox)
# );
## - if using postgres, you need also to create a trigger as follows:
## -
## - first create language plpgsql if not yet created:
## -
# CREATE LANGUAGE plpgsql;
#
# CREATE OR REPLACE FUNCTION merge_expires() RETURNS TRIGGER AS \$\$
# BEGIN
# UPDATE expires SET expire_stamp = NEW.expire_stamp
# WHERE username = NEW.username AND mailbox = NEW.mailbox;
# IF FOUND THEN
# RETURN NULL;
# ELSE
# RETURN NEW;
# END IF;
# END;
# \$\$ LANGUAGE plpgsql;
#
# CREATE TRIGGER mergeexpires BEFORE INSERT ON expires
# FOR EACH ROW EXECUTE PROCEDURE merge_expires();
map {
pattern = shared/expire/\$user/\$mailbox
table = expires
value_field = expire_stamp
fields {
username = \$user
mailbox = \$mailbox
}
}
EOF
if [[ "$?" -gt 0 ]]; then
_failed=true
fi
fi
cat <<EOF >> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
# CREATE TABLE user_shares (
# from_user varchar(100) not null,
# to_user varchar(100) not null,
# dummy char(1) DEFAULT '1', -- always '1' currently
# primary key (from_user, to_user)
# );
# COMMENT ON TABLE user_shares IS 'User from_user shares folders to user to_user.';
#
# CREATE TABLE anyone_shares (
# from_user varchar(100) not null,
# dummy char(1) DEFAULT '1', -- always '1' currently
# primary key (from_user)
# );
# COMMENT ON TABLE anyone_shares IS 'User from_user shares folders to anyone.';
map {
pattern = shared/shared-boxes/user/\$to/\$from
table = user_shares
value_field = dummy
fields {
from_user = \$from
to_user = \$to
}
}
map {
pattern = shared/shared-boxes/anyone/\$from
table = anyone_shares
value_field = dummy
fields {
from_user = \$from
}
}
EOF
if [[ "$?" -gt 0 ]]; then
_failed=true
fi
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Recreating file /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext failed"
fi
elif [ "$db_driver" = "mysql" ]; then
## - adjust/renew file /usr/local/dovecot/etc/dovecot/sql-dict.conf.ext
## -
cat <<EOF >/usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
connect = host=$dbhost user=$dbuser password=$dbpassword dbname=$dbname
# CREATE TABLE quota2 (
# username varchar(100) not null,
# bytes bigint not null default 0,
# messages integer not null default 0,
# primary key (username)
# );
map {
pattern = priv/quota/storage
table = quota2
username_field = username
value_field = bytes
}
map {
pattern = priv/quota/messages
table = quota2
username_field = username
value_field = messages
}
EOF
if [[ "$?" -gt 0 ]]; then
_failed=true
fi
if $plugin_expire ; then
cat <<EOF >> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
# CREATE TABLE expires (
# username varchar(100) not null,
# mailbox varchar(255) not null,
# expire_stamp integer not null,
# primary key (username, mailbox)
# );
map {
pattern = shared/expire/\$user/\$mailbox
table = expires
value_field = expire_stamp
fields {
username = \$user
mailbox = \$mailbox
}
}
EOF
if [[ "$?" -gt 0 ]]; then
_failed=true
fi
fi
cat <<EOF >> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
# CREATE TABLE user_shares (
# from_user varchar(100) not null,
# to_user varchar(100) not null,
# dummy char(1) DEFAULT '1', -- always '1' currently
# primary key (from_user, to_user)
# ) COMMENT = 'User from_user shares folders to user to_user.';
#
# CREATE TABLE anyone_shares (
# from_user varchar(100) not null,
# dummy char(1) DEFAULT '1', -- always '1' currently
# primary key (from_user)
# ) COMMENT = 'User from_user shares folders to anyone.';
map {
pattern = shared/shared-boxes/user/\$to/\$from
table = user_shares
value_field = dummy
fields {
from_user = \$from
to_user = \$to
}
}
map {
pattern = shared/shared-boxes/anyone/\$from
table = anyone_shares
value_field = dummy
fields {
from_user = \$from
}
}
EOF
if [[ "$?" -gt 0 ]]; then
_failed=true
fi
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Recreating file /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext failed"
fi
fi
## -
## - End: Using SQL dictionary
## ------------------------------------------------------------------------
## -----------------
## --- Configure managesieve support for dovecot
# edit /usr/local/dovecot/etc/dovecot/conf.d/20-managesieve.conf
#
_failed=false
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Configure managesieve '20-managesieve.conf'.."
echo -e "$rc_not_yet_implemented"
else
## - edit /usr/local/dovecot/etc/dovecot/conf.d/20-managesieve.conf
## -
## - service managesieve-login {
## - inet_listener sieve {
## - #address = 127.0.0.1 $ipv4 $ipv6
## - address = 127.0.0.1
## - port = 4190
## - }
## - ..
## - }
## -
echononl " Configure managesieve '20-managesieve.conf'.."
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(service managesieve-login\ +{.*)#\1service managesieve-login {#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-managesieve.conf || _failed=true
if [[ -n "$ipv6" ]]; then
perl -i -n -p -e "s#^([ ]*)\#?\ ?(inet_listener\ +sieve\ +{.*)#\1inet_listener sieve {\n\1 \#address = 127.0.0.1 $ipv4 $ipv6\n\1 address = 127.0.0.1\n\1 port = 4190\n\1}\n\1\#\# \2#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-managesieve.conf || _failed=true
else
perl -i -n -p -e "s#^([ ]*)\#?\ ?(inet_listener\ +sieve\ +{.*)#\1inet_listener sieve {\n\1 \#address = 127.0.0.1 $ipv4\n\1 address = 127.0.0.1\n\1 port = 4190\n\1}\n\1\#\# \2#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-managesieve.conf || _failed=true
fi
perl -i -n -p -e "s#^([ ]*\#?\ ?vsz_limit.*)#\1\n}#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-managesieve.conf || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(service managesieve\ +{.*)#\1service managesieve {#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-managesieve.conf || _failed=true
# since divecot 2.2.4: process_count changed to process_limit.
#
#perl -i -n -p -e "s#^([ ]*\#?\ ?process_count.*)#\1\n}#g" \
# /usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-managesieve.conf || _failed=true
perl -i -n -p -e "s#^([ ]*\#?\ ?process_limit.*)#\1\n}#g" \
/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-managesieve.conf || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-managesieve.conf failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/20-managesieve.conf
#_set_link=""
#echo
#echo "Set symlink "
#echo -e -n " /usr/local/dovecot --> dovecot-${_version} /usr/local/dovecot? [y/n]: "
#read _set_link
#if [ "y" = "$_set_link" -o "Y" = "$_set_link" -o "Yes" = "$_set_link" -o "yes" = "$_set_link" ];then
# echononl " Create symlink.."
# rm -f /usr/local/dovecot
# ln -s dovecot-${_version} /usr/local/dovecot
# if [ "$?" = 0 ]; then
# echo -e "$rc_done"
# else
# echo -e "$rc_failed"
# fatal "Creating Symlink /usr/local/dovecot --> dovecot-${_version} /usr/local/dovecot failed"
# fi
#fi
## - Add a cronjob to check if certifice/key for dovecot service is-up-to-date
## -
echononl " Create cronjob for checking if certifice/key for dovecot service is-up-to-date"
if [[ -f "$_backup_crontab_file" ]] ; then
if ! grep -e "/root/bin/monitoring/check_cert_for_dovecot.sh" "$_backup_crontab_file" > /dev/null ; then
echo "" >> $_backup_crontab_file
echo "# - Check if cert/key for dovecot service is up-to-date" >> $_backup_crontab_file
echo "# -" >> $_backup_crontab_file
echo "46 05 * * * /root/bin/monitoring/check_cert_for_dovecot.sh" >> $_backup_crontab_file
crontab $_backup_crontab_file
echo -e "$rc_done"
else
echo -e "$rc_skipped"
fi
else
_crontab_tmp_file=/tmp/crontab_root.$$
crontab -l > $_crontab_tmp_file 2> /dev/null
if [[ ! -s $_crontab_tmp_file ]]; then
echo "PATH=/usr/local/dovecot/bin:$PATH" > $_crontab_tmp_file
fi
if ! grep -e "/root/bin/monitoring/check_cert_for_dovecot.sh" $_crontab_tmp_file > /dev/null ; then
echo "" >> $_crontab_tmp_file
echo "# - Check if cert/key for dovecot service is up-to-date" >> $_crontab_tmp_file
echo "# -" >> $_crontab_tmp_file
echo "46 05 * * * /root/bin/monitoring/check_cert_for_dovecot.sh" >> $_crontab_tmp_file
crontab $_crontab_tmp_file
echo -e "$rc_done"
else
echo -e "$rc_skipped"
fi
rm -f $_crontab_tmp_file
fi
echononl " Run script 'check_cert_for_dovecot.sh' if possible.."
if [[ -x "/root/bin/monitoring/check_cert_for_dovecot.sh" ]] ; then
/root/bin/monitoring/check_cert_for_dovecot.sh > $log_file 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "$(cat "$log_file")"
echononl " continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Abbruch durch User"
fi
else
echo -e "$rc_skipped"
fi
blank_line
echononl " Create symlink '/usr/local/dovecot' --> 'dovecot-${_version}'.."
rm -f /usr/local/dovecot
ln -s dovecot-${_version} /usr/local/dovecot
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Creating Symlink /usr/local/dovecot --> dovecot-${_version} /usr/local/dovecot failed"
fi
#_restart=""
#echo
#echo -e -n "Start/Restart services (dovecot/postfix)? [y/n]: "
#read _restart
#if [ "y" = "$_restart" -o "Y" = "$_restart" -o "Yes" = "$_restart" -o "yes" = "$_restart" ];then
# echononl " Start dovecot service.."
# if $systemd_support ; then
# systemctl start dovecot
# else
# /etc/init.d/dovecot start > /dev/null 2>&1
# fi
# if [ "$?" = 0 ]; then
# echo -e "$rc_done"
# else
# echo -e "$rc_failed"
# error "Starting dovecot service failed"
# fi
# echononl " Restart postfix.."
# if $SYSTEMD_EXISTS ; then
# systemctl restart postfix
# else
# /etc/init.d/postfix restart > /dev/null 2>&1
# fi
# if [ "$?" = 0 ]; then
# echo -e "$rc_done"
# else
# echo -e "$rc_failed"
# fatal "Restarting postfix failed"
# fi
#fi
echononl " Start dovecot service.."
if $systemd_support ; then
systemctl start dovecot
else
/etc/init.d/dovecot start > /dev/null 2>&1
fi
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Starting dovecot service failed"
fi
echononl " Restart postfix.."
if $SYSTEMD_EXISTS ; then
systemctl restart postfix
else
/etc/init.d/postfix restart > /dev/null 2>&1
fi
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Restarting postfix failed"
fi
blank_line
echononl " Set '_update=true' in file '$(basename "$conf_file")'.."
if grep -q -E "^\s*_update=false" "$conf_file" 2> /dev/null ; then
perl -i -n -p -e "s/^\s*_update=.*/_update=true/" "$conf_file"
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Adjusting '"$conf_file"' (set _update=true) failed!"
fi
else
echo -e "$rc_skipped"
fi
echo -e "
\033[33m\033[1mNotice:\033[m
The Dovecot Service is configured to support more than 128 simultanously connections.
So, you have to \033[1mincrease /proc/sys/fs/inotify/max_user_instances\033[m (default is 128):
# echo \"fs.inotify.max_user_instances = 2048\" >> /etc/sysctl.conf
# sysctl -p
If you are running dovecot on a Virtual Guest System, you have to do that on the
Host (Root) System.
"
clean_up 0