Files
mailsystem/install_update_dovecot-2.4.sh

11121 lines
321 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 ]"
rc_already_done="\033[71G[ \033[32mAlready Done\033[m ]"
rc_not_needed_anymore="\033[71G[ \033[1;37mNot Needed Anymore\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[37m\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
}
# ------------------------------------------------------------------------------
# Funktion: replace_or_append_code_block_if_keyval
#
# Beschreibung:
# Ersetzt einen benannten Codeblock in einer Konfigurationsdatei durch einen
# neuen Block, **aber nur**, wenn im Hauptblock (nicht in Unterblöcken)
# ein bestimmtes Key-Value-Paar (z.B. "type = shared") vorhanden ist.
#
# Wenn kein passender Block gefunden wird (also kein Block mit dem Namen existiert),
# wird der neue Block **am Ende der Datei angehängt**.
#
# Wenn der Block vorhanden ist, das Key-Value-Paar aber **nicht** mit dem
# erwarteten Wert übereinstimmt, bleibt der Originalblock **unverändert**
# und der neue Block wird trotzdem **angehängt**.
#
# Parameter:
# $1 - Name des Blocks (z.B. "mailbox INBOX")
# $2 - Neuer Blockinhalt (als String)
# $3 - Pfad zur Datei, in der der Block ersetzt werden soll
# $4 - Schlüssel, nach dem im Hauptblock gesucht werden soll
# $5 - Erwarteter Wert des Schlüssels
#
# Rückgabewerte:
# 0 - Erfolgreich ersetzt oder angehängt
# 1 - Ungültige Parameter
# 2 - Datei existiert nicht
# 3 - Kein passender Block gefunden → wurde angehängt
#
# Hinweise:
# - Die Prüfung auf key = value erfolgt nur auf oberster Blockebene.
# - Diese Funktion ist großzügiger als "replace_code_block_if_keyval_strict":
# Sie ersetzt, wenn Bedingung erfüllt ist hängt aber auch an, wenn nicht.
# ------------------------------------------------------------------------------
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 und 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
}
# ------------------------------------------------------------------------------
# Funktion: replace_code_block_if_keyval
#
# Beschreibung:
# Ersetzt einen benannten Codeblock in einer Konfigurationsdatei durch einen
# neuen Block, aber **nur**, wenn innerhalb des Hauptblocks (nicht in Unterblöcken)
# ein bestimmtes Key-Value-Paar vorhanden ist (z.B. "type = shared").
#
# Wenn der Block nicht vorhanden ist oder das Key-Value-Paar nicht übereinstimmt,
# wird **nichts verändert**.
#
# Parameter:
# $1 - Name des Blocks (z.B. "mailbox INBOX")
# $2 - Neuer Blockinhalt (als String)
# $3 - Pfad zur Datei, in der der Block ersetzt werden soll
# $4 - Schlüssel, nach dem im Hauptblock gesucht werden soll
# $5 - Erwarteter Wert des Schlüssels
#
# Rückgabewert:
# 0 - Erfolgreich ersetzt oder keine Änderung nötig
# 1 - Ungültige Parameter
# 2 - Datei existiert nicht
#
# Hinweis:
# Der neue Block muss korrekt formatiert sein (einschließlich öffnender Klammer).
# Der Block wird **nicht** angehängt, falls er fehlt oder die Bedingung nicht zutrifft.
# ------------------------------------------------------------------------------
replace_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_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)
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"
# Nur im Hauptblock prüfen
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
} else {
printf "%s", block_buffer
}
next
}
next
}
print
}
' "$file" > "$tmp_file"
mv "$tmp_file" "$file"
#echo "Ersetzung abgeschlossen (nur wenn Bedingung erfüllt war)."
return 0
}
# ------------------------------------------------------------------------------
# Funktion: replace_or_appen_dcode_block_if_keyval_strict
#
# Beschreibung:
# Ersetzt einen benannten Codeblock in einer Konfigurationsdatei durch einen
# neuen Block, aber **nur**, wenn innerhalb des Hauptblocks ein bestimmtes
# Key-Value-Paar (z.B. "type = shared") vorhanden ist.
#
# Wenn ein Block mit dem gesuchten Namen vorhanden ist, der angegebene Key aber
# einen **abweichenden Wert** hat (z.B. "type = private"), wird **nichts verändert**
# und der Block **wird nicht ersetzt und nicht angehängt**.
#
# Wenn kein passender Block vorhanden ist (also weder mit noch ohne Key),
# wird der neue Block **am Ende der Datei angehängt**.
#
# Parameter:
# $1 - Name des Blocks (z.B. "mailbox INBOX")
# $2 - Neuer Blockinhalt (als String)
# $3 - Pfad zur Datei, in der der Block ersetzt werden soll
# $4 - Schlüssel, nach dem im Hauptblock gesucht werden soll
# $5 - Erwarteter Wert des Schlüssels
#
# Rückgabewerte:
# 0 - Block ersetzt oder angehängt oder keine Änderung (weil Bedingung nicht erfüllt)
# 1 - Ungültige Parameter
# 2 - Datei existiert nicht
# 3 - Kein Block gefunden → wurde am Ende angehängt
# 4 - Block gefunden, aber Bedingung nicht erfüllt → keine Änderung vorgenommen
#
# Hinweise:
# - Die Bedingung wird nur im äußeren Block-Level geprüft (nicht in Unterblöcken).
# - Falls du mehrere Bedingungen prüfen willst, muss die Funktion erweitert werden.
# ------------------------------------------------------------------------------
replace_or_append_code_block_if_keyval_strict() {
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_code_block_if_keyval_strict \"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)
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_key = 0
matching_keyval = 0
next
}
if (in_block) {
brace_depth += count_char($0, "{") - count_char($0, "}")
block_buffer = block_buffer $0 "\n"
if (brace_depth == 1 && match($0, "^\\s*" req_key "\\s*=\\s*")) {
found_key = 1
if ($0 ~ "^\\s*" req_key "\\s*=\\s*" req_val "\\s*$") {
matching_keyval = 1
}
}
if (brace_depth <= 0) {
in_block = 0
block_seen = 1
if (found_key) {
if (matching_keyval) {
print new_block
block_replaced = 1
} else {
printf "%s", block_buffer
block_invalid = 1
}
} else {
printf "%s", block_buffer
}
next
}
next
}
print
}
END {
if (!block_seen) {
print new_block > "/dev/stderr"
exit 3
}
if (block_invalid && !block_replaced) {
print "WARNUNG: Block vorhanden, aber Bedingung nicht erfüllt. Kein Ersetzen und kein Anhängen." > "/dev/stderr"
exit 4
}
}
' "$file" 1>"$tmp_file" 2>_new_block_to_append.tmp
result=$?
if [[ $result -eq 3 ]]; then
# Kein passender Block gefunden -> Anfügen
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 wurde daher am Ende angehängt."
return 0
elif [[ $result -eq 4 ]]; then
# Block gefunden, aber Bedingung nicht erfüllt -> nichts tun
rm -f "$tmp_file" _new_block_to_append.tmp
echo "Block '$block_name' vorhanden, aber Bedingung '$required_key = $required_value' nicht erfüllt. Keine Änderung vorgenommen."
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%-*}"
# '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 [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
postmaster_address="${postmaster_address/\\@/@}"
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
}
# ------------------------------------------------------------------------------
# Funktion: replace_or_append_code_block_if_keyval
#
# Beschreibung:
# Ersetzt einen benannten Codeblock in einer Konfigurationsdatei durch einen
# neuen Block, **aber nur**, wenn im Hauptblock (nicht in Unterblöcken)
# ein bestimmtes Key-Value-Paar (z.B. "type = shared") vorhanden ist.
#
# Wenn kein passender Block gefunden wird (also kein Block mit dem Namen existiert),
# wird der neue Block **am Ende der Datei angehängt**.
#
# Wenn der Block vorhanden ist, das Key-Value-Paar aber **nicht** mit dem
# erwarteten Wert übereinstimmt, bleibt der Originalblock **unverändert**
# und der neue Block wird trotzdem **angehängt**.
#
# Parameter:
# $1 - Name des Blocks (z.B. "mailbox INBOX")
# $2 - Neuer Blockinhalt (als String)
# $3 - Pfad zur Datei, in der der Block ersetzt werden soll
# $4 - Schlüssel, nach dem im Hauptblock gesucht werden soll
# $5 - Erwarteter Wert des Schlüssels
#
# Rückgabewerte:
# 0 - Erfolgreich ersetzt oder angehängt
# 1 - Ungültige Parameter
# 2 - Datei existiert nicht
# 3 - Kein passender Block gefunden → wurde angehängt
#
# Hinweise:
# - Die Prüfung auf key = value erfolgt nur auf oberster Blockebene.
# - Diese Funktion ist großzügiger als "replace_code_block_if_keyval_strict":
# Sie ersetzt, wenn Bedingung erfüllt ist hängt aber auch an, wenn nicht.
# ------------------------------------------------------------------------------
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 und 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
}
# ------------------------------------------------------------------------------
# Funktion: replace_code_block_if_keyval
#
# Beschreibung:
# Ersetzt einen benannten Codeblock in einer Konfigurationsdatei durch einen
# neuen Block, aber **nur**, wenn innerhalb des Hauptblocks (nicht in Unterblöcken)
# ein bestimmtes Key-Value-Paar vorhanden ist (z.B. "type = shared").
#
# Wenn der Block nicht vorhanden ist oder das Key-Value-Paar nicht übereinstimmt,
# wird **nichts verändert**.
#
# Parameter:
# $1 - Name des Blocks (z.B. "mailbox INBOX")
# $2 - Neuer Blockinhalt (als String)
# $3 - Pfad zur Datei, in der der Block ersetzt werden soll
# $4 - Schlüssel, nach dem im Hauptblock gesucht werden soll
# $5 - Erwarteter Wert des Schlüssels
#
# Rückgabewert:
# 0 - Erfolgreich ersetzt oder keine Änderung nötig
# 1 - Ungültige Parameter
# 2 - Datei existiert nicht
#
# Hinweis:
# Der neue Block muss korrekt formatiert sein (einschließlich öffnender Klammer).
# Der Block wird **nicht** angehängt, falls er fehlt oder die Bedingung nicht zutrifft.
# ------------------------------------------------------------------------------
replace_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_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)
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"
# Nur im Hauptblock prüfen
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
} else {
printf "%s", block_buffer
}
next
}
next
}
print
}
' "$file" > "$tmp_file"
mv "$tmp_file" "$file"
#echo "Ersetzung abgeschlossen (nur wenn Bedingung erfüllt war)."
return 0
}
# ------------------------------------------------------------------------------
# Funktion: replace_or_appen_dcode_block_if_keyval_strict
#
# Beschreibung:
# Ersetzt einen benannten Codeblock in einer Konfigurationsdatei durch einen
# neuen Block, aber **nur**, wenn innerhalb des Hauptblocks ein bestimmtes
# Key-Value-Paar (z.B. "type = shared") vorhanden ist.
#
# Wenn ein Block mit dem gesuchten Namen vorhanden ist, der angegebene Key aber
# einen **abweichenden Wert** hat (z.B. "type = private"), wird **nichts verändert**
# und der Block **wird nicht ersetzt und nicht angehängt**.
#
# Wenn kein passender Block vorhanden ist (also weder mit noch ohne Key),
# wird der neue Block **am Ende der Datei angehängt**.
#
# Parameter:
# $1 - Name des Blocks (z.B. "mailbox INBOX")
# $2 - Neuer Blockinhalt (als String)
# $3 - Pfad zur Datei, in der der Block ersetzt werden soll
# $4 - Schlüssel, nach dem im Hauptblock gesucht werden soll
# $5 - Erwarteter Wert des Schlüssels
#
# Rückgabewerte:
# 0 - Block ersetzt oder angehängt oder keine Änderung (weil Bedingung nicht erfüllt)
# 1 - Ungültige Parameter
# 2 - Datei existiert nicht
# 3 - Kein Block gefunden → wurde am Ende angehängt
# 4 - Block gefunden, aber Bedingung nicht erfüllt → keine Änderung vorgenommen
#
# Hinweise:
# - Die Bedingung wird nur im äußeren Block-Level geprüft (nicht in Unterblöcken).
# - Falls du mehrere Bedingungen prüfen willst, muss die Funktion erweitert werden.
# ------------------------------------------------------------------------------
replace_or_append_code_block_if_keyval_strict() {
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_code_block_if_keyval_strict \"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)
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_key = 0
matching_keyval = 0
next
}
if (in_block) {
brace_depth += count_char($0, "{") - count_char($0, "}")
block_buffer = block_buffer $0 "\n"
if (brace_depth == 1 && match($0, "^\\s*" req_key "\\s*=\\s*")) {
found_key = 1
if ($0 ~ "^\\s*" req_key "\\s*=\\s*" req_val "\\s*$") {
matching_keyval = 1
}
}
if (brace_depth <= 0) {
in_block = 0
block_seen = 1
if (found_key) {
if (matching_keyval) {
print new_block
block_replaced = 1
} else {
printf "%s", block_buffer
block_invalid = 1
}
} else {
printf "%s", block_buffer
}
next
}
next
}
print
}
END {
if (!block_seen) {
print new_block > "/dev/stderr"
exit 3
}
if (block_invalid && !block_replaced) {
print "WARNUNG: Block vorhanden, aber Bedingung nicht erfüllt. Kein Ersetzen und kein Anhängen." > "/dev/stderr"
exit 4
}
}
' "$file" 1>"$tmp_file" 2>_new_block_to_append.tmp
result=$?
if [[ $result -eq 3 ]]; then
# Kein passender Block gefunden -> Anfügen
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 wurde daher am Ende angehängt."
return 0
elif [[ $result -eq 4 ]]; then
# Block gefunden, aber Bedingung nicht erfüllt -> nichts tun
rm -f "$tmp_file" _new_block_to_append.tmp
#echo "Block '$block_name' vorhanden, aber Bedingung '$required_key = $required_value' nicht erfüllt. Keine Änderung vorgenommen."
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
}
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
echononl " Disable dovecot service.."
if systemctl list-units --full -all | grep -Fq "dovecot.service" 2> /dev/null ; then
if $systemd_support ; then
systemctl disable dovecot > /dev/null 2>&1
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Stopping dovecot service failed"
fi
else
echo -e "$rc_skipped"
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
elif [[ -f "/usr/lib/systemd/system/dovecot.service" ]] ; then
rm -f "/usr/lib/systemd/system/dovecot.service" > /dev/null 2>&1
if [[ "$?" -gt 0 ]]; then
echo -e "$rc_failed"
error "Removing file '/usr/lib/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
elif [[ -f "/usr/lib/systemd/system/dovecot.socket" ]] ; then
rm -f "/usr/lib/systemd/system/dovecot.socket" > /dev/null 2>&1
if [[ "$?" -gt 0 ]]; then
echo -e "$rc_failed"
error "Removing systemd's socket file '/usr/lib/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
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## Mail Location ans Namespace Settigs
##
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
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
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## SSL settings
##
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## Mailbox definitions
##
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-auth.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## Authentication processes
##
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/auth-sql.conf.ext"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## Authentication for SQL users. Included from 10-auth.conf.
##
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-logging.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
_failed=false
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## Log destination.
##
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-lda.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
_failed=false
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## LDA specific settings (also used by LMTP)
##
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-lmtp.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
_failed=false
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## LMTP specific settings
##
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-imap.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
_failed=false
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## IMAP specific settings
##
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-pop3.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
_failed=false
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## POP3 specific settings
##
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-sieve.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
_failed=false
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## Settings for the Sieve interpreter
##
# see also: https://doc.dovecot.org/2.4.1/core/plugins/sieve.html
# To use Sieve, you will first need to make sure you are using Dovecot LDA or LMTP Server
# for delivering incoming mail to users' mailboxes.
#
# Then, you need to enable the Sieve plugin in your configuration:
#
# protocol lda {
# mail_plugins {
# sieve = yes
# }
# }
#
# protocol lmtp {
# mail_plugins {
# sieve = yes
# }
# }
# Script storage
# ==============
#
# Sieve scripts are retrieved from a script storage. This can currently be the local
# filesystem, an LDAP database or any dict storage. Depending on the storage
# implementation, its type and its configuration, storages can contain one script,
# several scripts identified by name, and a series of scripts in a well-defined order
# to be executed in sequence.
#
# Script storages are configured in a named sieve_script block:
#
# sieve_script personal {
# path = ~/.dovecot.sieve
# }
#
# The storage name (personal in the example) is used internally within configurations,
# as an identifier for logging, and as an identifier for command line tools. It also
# allows updating a storage that was defined earlier - by repeating the sieve_script
# block and adding additional configuration settings - or it allows userdb to override
# storage settings for specific users.
#
# Script storage types
# --------------------
#
# Sieve scripts can be evaluated at various stages in message delivery and for stored
# messages. The type of the Sieve script storage determines where it is applicable,
# how the storage is accessed and how the retrieved Sieve script is evaluated.
#
# The type of the Sieve script storage is configured using the sieve_script_type setting.
# The following types are currently recognized (others are defined by the sieve-imapsieve
# plugin):
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/95-sieve-vacation.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
_failed=false
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## Settings for the Sieve Vacation Extension
##
# see also: https://doc.dovecot.org/2.4.1/core/config/sieve/extensions/vacation.html
# The Sieve vacation extension (RFC 5230) defines a mechanism to generate automatic
# replies to incoming email messages. It takes various precautions to make sure replies
# are only sent when appropriate.
#
# Script authors can specify how often replies can be sent to a particular contact.
# In the original vacation extension, this interval is specified in days with a minimum
# of one day. When more granularity is necessary and particularly when replies must be
# sent more frequently than one day, the vacation-seconds extension (RFC 6131) can be
# used. This allows specifying the minimum reply interval in seconds with a minimum of
# zero (a reply is then always sent), depending on administrator configuration.
#
# Configuration
# =============
#
# The vacation extension is available by default.
#
# In contrast, the vacation-seconds extension - which implies the vacation extension
# when used - is not available by default and needs to be enabled explicitly by adding
# it to sieve_extensions.
#
# The configuration also needs to be adjusted accordingly to allow a non-reply period of
# less than a day.
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-quota.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
_failed=false
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## Quota configuration.
##
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-acl.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
_failed=false
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## Mailbox access control lists (ACL)
##
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
fi
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-managesieve.conf"
echononl " Create empty file '$(basename "${_conf_file}")'.."
if [[ ! -f "${_conf_file}" ]] ; then
_failed=false
cat <<'EOF' > "${_conf_file}" 2> "${log_file}"
##
## ManageSieve specific settings
##
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Creating file '${_conf_file}' failed!"
fi
else
echo -e "$rc_skipped"
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
## -
_file="/etc/profile"
_block='checkdir="/usr/local/dovecot/bin"
if [ -d "$checkdir" ]; then
PATH=${check_dir}:$PATH
fi'
echononl " Add /usr/local/dovecot/bin to PATH variable.."
if grep -Eq '^\s*checkdir="?/usr/local/dovecot/bin"?$' "${_file}"; then
echo -e "$rc_skipped"
else
cp "${_file}" "/tmp/etc_profile.${backup_date}" > "${log_file}" 2<&1
if [[ $? -gt 0 ]] ; then
echo -e "$rc_failed"
error "$(cat $log_file)"
else
awk -v b="${_block}" '
/^export PATH/ {
print b;
print "";
}
{ print }
' "/tmp/etc_profile.${backup_date}" > "${_file}"
if [[ $? -gt 0 ]] ; then
echo -e "$rc_failed"
error "Adding /usr/local/dovecot/bin to PATH variable failed!"
else
echo -e "$rc_done"
fi
fi
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 Copying thr sample config files to the configuration directory 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 The backup of the main configuration file 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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf"
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
# - }
# -
echononl " Delete block 'namespace inbox' in file '$(basename "${_conf_file}")'.."
if grep -qE '^\s*namespace\s+inbox\s*{' "${_conf_file}"; then
delete_code_block_with_comments "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
echononl " Delete block 'passdb pam' in file '$(basename "${_conf_file}")'.."
if grep -qE '^\s*passdb\s+pam\s*{' "${_conf_file}"; then
delete_code_block_with_comments "passdb pam" "${_conf_file}"
if [[ $? -gt 1 ]] ; then
echo -e "$rc_failed"
error "Deleting block 'passdb pam' 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}"
read -r -d '' NEW_BLOCK <<'EOF'
import_environment {
TZ = :/etc/localtime
}
EOF
if grep -qE "^\s*quota \"User quota\"\s+{" "${_conf_file}"; then
replace_code_block 'quota "User quota"' "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# TZ (timezone) Environment Variable
#
# The use of the TZ environment variable can dramatically reduce the number
# of system calls and kernel context switches performed by the application.
#
# The localtime() function in glibc checks whether the TZ environment variable
# is set. If it is not set, then glibc will use the stat() system call every
# time localtime() is called, even with vDSO in place.
#
# Setting the TZ environment variable to :/etc/localtime (or some other
# timezone file of your choice) for a process will save glibc from making those
# extra unnecessary system calls (Notice the column : prefix before the file path).
$(echo -e "${NEW_BLOCK}")
EOF
fi
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 Main configuration ($(basename "${_conf_file}")).."
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
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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf"
: > "${log_file}"
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-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 auth-xmpp {
# 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 Services ($(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 auth-xmpp {
listen = $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 = vmail
#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 Services ($(basename "${_conf_file}")).."
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 SSL ($(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 SSL ($(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
# - 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
_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 SSL ($(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
#
# maildir_broken_filename_sizes =
#
echononl " Adjusting base configurations ($(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
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
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
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
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
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
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
fi
read -r -d '' NEW_BLOCK <<'EOF'
mail_plugins {
acl = yes
quota = yes
}
EOF
if grep -qE "^\s*mail_plugins\s+{" "${_conf_file}"; then
replace_code_block "mail_plugins" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# A list of mail plugins to load.
$(echo -e "${NEW_BLOCK}")
EOF
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
fi
if grep -qE '^\s*maildir_broken_filename_sizes\s*=' "${_conf_file}" ; then
replace_variable \
"maildir_broken_filename_sizes" \
"yes" \
"${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]] ; then
_failed=true
fi
else
cat <<EOF >> "${_conf_file}" || _failed=true
# maildir_broken_filename_sizes
#
# If enabled, Dovecot doesn't use the S=<size> in the Maildir filenames for
# getting the mail's physical size, except when recalculating Maildir++ quota.
# This can be useful in systems where a lot of the Maildir filenames have a
# broken size. The performance hit for enabling this is very small.
#maildir_broken_filename_sizes = no
maildir_broken_filename_sizes = yes
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
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 base configurations ($(basename "${_conf_file}")).."
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(mail_location\ +=.*)#\1\#\# \2\n\1mail_location = maildir:/var/vmail/%d/%n/Maildir#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_uid.*)#\1\#\# \2\n\1mail_uid = vmail#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_gid.*)#\1\#\# \2\n\1mail_gid = vmail#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_temp_dir.*)#\1\#\# \2\n\1mail_temp_dir = /var/vmail/tmp#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(first_valid_uid.*)#\1\#\# \2\n\1first_valid_uid = 5000#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(last_valid_uid.*)#\1\#\# \2\n\1last_valid_uid = 5000#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(first_valid_gid.*)#\1\#\# \2\n\1first_valid_gid = 5000#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(last_valid_gid.*)#\1\#\# \2\n\1last_valid_gid = 5000#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(auth_socket_path\ +=.*)#\1\#\# \2\n\1auth_socket_path = /run/dovecot/auth-userdb#g" \
"${_conf_file}" || _failed=true
if $plugin_expire ; then
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota acl expire#g" \
"${_conf_file}" || _failed=true
else
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota acl#g" \
"${_conf_file}" || _failed=true
fi
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mailbox_list_index\s*=.*)#\1\#\# \2\n\1mailbox_list_index = yes#g" \
${_conf_file} || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file '$(basename "${_conf_file}")' 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 or add namespaces in 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
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 or add namespaces in file '$(basename "${_conf_file}")'.."
## - 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
## - }
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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-mailboxes.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/15-mailboxes.conf
#
# namespace inbox {
# These mailboxes are widely used and could perhaps be created automatically:
# mailbox Drafts {
# auto = subscribe
# special_use = \Drafts
# }
# mailbox Spam {
# auto = subscribe
# autoexpunge = 30d
# special_use = \Junk
# }
# mailbox Junk {
# auto = no
# autoexpunge = 30d
# special_use = \Junk
# }
# mailbox Trash {
# auto = subscribe
# autoexpunge = 3d
# special_use = \Trash
# }
#
# # For \Sent mailboxes there are two widely used names. We'll mark both of
# # them as \Sent. User typically deletes one of them if duplicates are created.
# mailbox Sent {
# auto = subscribe
# special_use = \Sent
# }
# mailbox "Sent Messages" {
# auto = no
# special_use = \Sent
# }
# }
echononl " Adjusting Mailboxes ($(basename "${_conf_file}"))"
read -r -d '' NEW_BLOCK <<'EOF'
namespace inbox {
# These mailboxes are widely used and could perhaps be created automatically:
mailbox Drafts {
auto = subscribe
special_use = \Drafts
}
mailbox Spam {
auto = subscribe
autoexpunge = 30d
special_use = \Junk
}
mailbox Junk {
auto = no
autoexpunge = 30d
special_use = \Junk
}
mailbox Trash {
auto = subscribe
autoexpunge = 3d
special_use = \Trash
}
# For \Sent mailboxes there are two widely used names. We'll mark both of
# them as \Sent. User typically deletes one of them if duplicates are created.
mailbox Sent {
auto = subscribe
special_use = \Sent
}
mailbox "Sent Messages" {
auto = no
special_use = \Sent
}
}
EOF
if grep -qE "^\s*namespace\s+inbox\s*{" "${_conf_file}"; then
replace_code_block "inbox" "${NEW_BLOCK}" "${_conf_file}"
if [[ $? -gt 0 ]]; then
_failed=true
fi
else
cat <<EOF >> "${_conf_file}" 2> "${log_file}"
# Each mailbox is specified in a separate mailbox section. The section name
# specifies the mailbox name. If it has spaces, you can put the name
# "in quotes". These sections can contain the following mailbox settings:
#
# auto:
# Indicates whether the mailbox with this name is automatically created
# implicitly when it is first accessed. The user can also be automatically
# subscribed to the mailbox after creation. The following values are
# defined for this setting:
#
# no - Never created automatically.
# create - Automatically created, but no automatic subscription.
# subscribe - Automatically created and subscribed.
#
# special_use:
# A space-separated list of SPECIAL-USE flags (RFC 6154) to use for the
# mailbox. There are no validity checks, so you could specify anything
# you want in here, but it's not a good idea to use flags other than the
# standard ones specified in the RFC:
#
# \All - This (virtual) mailbox presents all messages in the
# user's message store.
# \Archive - This mailbox is used to archive messages.
# \Drafts - This mailbox is used to hold draft messages.
# \Flagged - This (virtual) mailbox presents all messages in the
# user's message store marked with the IMAP \Flagged flag.
# \Important - This (virtual) mailbox presents all messages in the
# user's message store deemed important to user.
# \Junk - This mailbox is where messages deemed to be junk mail
# are held.
# \Sent - This mailbox is used to hold copies of messages that
# have been sent.
# \Trash - This mailbox is used to hold messages that have been
# deleted.
#
# comment:
# Defines a default comment or note associated with the mailbox. This
# value is accessible through the IMAP METADATA mailbox entries
# "/shared/comment" and "/private/comment". Users with sufficient
# privileges can override the default value for entries with a custom
# value.
# !! NOTE !!:
#
# Assumes "namespace inbox" has been defined (usally in 10-mail.conf).
$(echo -e "${NEW_BLOCK}")
EOF
if [[ $? -gt 0 ]]; then
_failed=true
fi
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/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 Mailboxes ($(basename "${_conf_file}"))"
perl -i.ORIG -n -p -e "s#^([ ]*)(mailbox\ +Drafts\ +{.*)#\1\2\n\1 auto = subscribe#g" \
${_conf_file} || _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" \
${_conf_file} || _failed=true
perl -i -n -p -e "s#^([ ]*)(mailbox\ +Junk\ +{.*)#\1\2\n\1 auto = no#g" \
${_conf_file} || _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" \
${_conf_file} || _failed=true
perl -i -n -p -e "s#^([ ]*)(mailbox\ +Junk\ +{.*)#\1\2\n\1 auto = no\n\1 autoexpunge = 30d#g" \
${_conf_file} || _failed=true
fi
else
if $plugin_expire ; then
perl -i -n -p -e "s#^([ ]*)(mailbox\ +$spam_folder\ +{.*)#\1\2\n\1 auto = subscribe#g" \
${_conf_file} || _failed=true
else
perl -i -n -p -e "s#^([ ]*)(mailbox\ +$spam_folder\ +{.*)#\1\2\n\1 auto = subscribe\n\1 autoexpunge = 30d#g" \
${_conf_file} || _failed=true
fi
fi
if $plugin_expire ; then
perl -i -n -p -e "s#^([ ]*)(mailbox\ +Trash\ +{.*)#\1\2\n\1 auto = subscribe#g" \
${_conf_file} || _failed=true
else
perl -i -n -p -e "s#^([ ]*)(mailbox\ +Trash\ +{.*)#\1\2\n\1 auto = subscribe\n\1 autoexpunge = 3d#g" \
${_conf_file} || _failed=true
fi
perl -i -n -p -e "s#^([ ]*)(mailbox\ +Sent\ +{.*)#\1\2\n\1 auto = subscribe#g" \
${_conf_file} || _failed=true
perl -i -n -p -e "s#^([ ]*)(mailbox\ +\"Sent Messages\"\ +{.*)#\1\2\n\1 auto = no#g" \
${_conf_file} || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting ${_conf_file} 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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-auth.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjusting Authentication ($(basename "${_conf_file}")).."
# edit /usr/local/dovecot/etc/dovecot/conf.d/10-auth.conf
#
# auth_allow_cleartext = no
# auth_allow_weak_schemes = ys
# auth_username_translation = "%@"
# auth_mechanisms = $auth_mechanisms
# !include auth-sql.conf.ext # !! comment all other includes
#
if grep -qE "^\s*auth_allow_cleartext\s*=" "${_conf_file}"; then
replace_variable "auth_allow_cleartext" "no" "${_conf_file}" || _failed=true
else
cat <<'EOF' >> "${_conf_file}" || _failed=true
# If no, disables the LOGIN command and all other cleartext authentication unless
# SSL/TLS is used (LOGINDISABLED capability) or the connection is secured (see ssl).
#
# This setting replaces the 'disable_plaintext_auth' setting.
auth_allow_cleartext = no
EOF
fi
if grep -qE "^\s*auth_allow_weak_schemes\s*=" "${_conf_file}"; then
replace_variable "auth_allow_weak_schemes" "yes" "${_conf_file}" || _failed=true
else
cat <<'EOF' >> "${_conf_file}" || _failed=true
# auth_allow_weak_schemes
#
# Default no
# Value boolean
# Changes Added: 2.4.0
#
# Controls whether password schemes marked as weak are allowed to be used. See
# Password Schemes for disabled by default schemes.
#
# If enabled, will emit warning to logs. If a disabled scheme is used, an error
# is logged.
#
# Notably, any explicitly cleartext schemes (such as PLAIN), CRAM-MD5, and
# DIGEST-MD5 are not affected by this setting.
auth_allow_weak_schemes = yes
EOF
fi
if grep -qE "^\s*auth_username_translation\s*=" "${_conf_file}"; then
replace_variable "auth_username_translation" "%@" "${_conf_file}" || _failed=true
else
cat <<'EOF' >> "${_conf_file}" || _failed=true
# If set, performs username character translations before querying the auth database.
#
# The value is a string formed of sets of from and to characters alternating.
#
# A value of #@/@ means that # and / will both be translated to the @ character.
auth_username_translation ="%@"
EOF
fi
if grep -qE "^\s*auth_mechanisms\s*=" "${_conf_file}"; then
replace_variable "auth_mechanisms" "${auth_mechanisms}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Cleartext Authentication
#
# The simplest authentication mechanism is PLAIN. The client simply sends the password
# unencrypted to Dovecot. All clients support the PLAIN mechanism, but obviously there's
# the problem that anyone listening on the network can steal the password. For that
# reason (and some others) other mechanisms were implemented.
#
# Today however many people use SSL, and there's no problem with sending unencrypted
# password inside SSL secured connections. So if you're using SSL, you probably don't
# need to bother worrying about anything else than the PLAIN mechanism.
#
# Another cleartext mechanism is LOGIN. It's typically used only by SMTP servers to let
# Outlook clients perform SMTP authentication. Note that LOGIN mechanism is not the
# same as IMAP's LOGIN command. The LOGIN command is internally handled using PLAIN
# mechanism.
#
# see https://doc.dovecot.org/2.4.1/core/config/auth/mechanisms/overview.html for
# further (non-rcCleartext) Authentication.
auth_mechanisms = ${auth_mechanisms}
EOF
fi
if grep -qE "^\s*\!include\s+" "${_conf_file}"; then
sed -i "s|^!include[[:space:]]\+.*$|!include auth-sql.conf.ext|" "${_conf_file}"
else
cat <<'EOF' >> "${_conf_file}" || _failed=true
##
## Password and user databases
##
#
# Password database is used to verify user's password (and nothing more).
# You can have multiple passdbs and userdbs. This is useful if you want to
# allow both system users (/etc/passwd) and virtual users to login without
# duplicating the system users into virtual database.
#
# <doc/wiki/PasswordDatabase.txt>
#
# User database specifies where mails are located and what user/group IDs
# own them. For single-UID configuration use "static" userdb.
#
# <doc/wiki/UserDatabase.txt>
!include auth-sql.conf.ext
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-auth.conf
## -
## - disable_plaintext_auth = no
## - auth_mechanisms = $auth_mechanisms
## - !include auth-sql.conf.ext # comment all other includes
## - auth_username_translation = "%@"
## -
echononl " Adjusting Authentication ($(basename "${_conf_file}")).."
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(disable_plaintext_auth\ +=.*)#\1\#\# \2\n\1disable_plaintext_auth = yes#" \
${_conf_file} || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(auth_mechanisms\ +=.*)#\1\#\# \2\n\1auth_mechanisms = $auth_mechanisms#g" \
${_conf_file} || _failed=true
perl -i -n -p -e "s#^(\!include\ auth-.*)#\#\1#g" \
${_conf_file} || _failed=true
perl -i -n -p -e "s#^\#(\!include\ auth-sql.*)#\1#g" \
${_conf_file} || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(auth_username_translation\ +=.*)#\1\#\# \2\n\1auth_username_translation = \"%@\"#g" \
${_conf_file} || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting ${_conf_file} 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
#
_failed=false
_conf_file="/usr/local/dovecot-${_version}/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
# edit /usr/local/dovecot/etc/dovecot/conf.d/auth-sql.conf.ext
#
# passdb_name = sql
# passdb sql {
# driver = sql
#
# # Path for SQL configuration file
# args = /usr/local/dovecot/etc/dovecot/sql-connect.conf.ext
# }
#
# userdb_name = sql
# passdb sql {
# driver = sql
#
# # Path for SQL configuration file
# args = /usr/local/dovecot/etc/dovecot/sql-connect.conf.ext
# }
#
# !! Note !!
#
# Ther above settings are equivalent to the following settins:
#
# passdb_name = sql
# passdb_driver = sql
# passdb_args = /usr/local/dovecot/etc/dovecot/sql-connect.conf.ext
#
# userdb_name = sql
# userdb_driver = sql
# userdb_args = /usr/local/dovecot/etc/dovecot/sql-connect.conf.ext
echononl " Adjusting SQL auth '$(basename "${_conf_file}")'.."
if [[ "$db_driver" = "pgsql" ]]; then
read -r -d '' NEW_BLOCK <<'EOF'
passdb sql {
# Load SQL connection data
!include /usr/local/dovecot-2.4.1-4/etc/dovecot/sql-connect.conf.ext
query = SELECT username AS user, password \\
FROM mailbox \\
WHERE username = '%{user}' AND active = true
}
EOF
if grep -qE "^\s*passdb\s+sql\s+{" "${_conf_file}"; then
replace_code_block "passdb sql" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Dovecot uses passdb and userdb as part of the authentication process.
#
# passdb authenticates the user. It also provides any other pre-login information
# needed for users, such as:
#
# - Which server user is proxied to.
# - If user should be allowed to log in at all (temporarily or permanently).
#
# Passdb Lookups Dovecot Proxy Dovecot Backend
# ----------------------------------------------------------
# IMAP & POP3 logins YES YES
# LMTP mail delivery YES YES
# doveadm commands YES YES
#
# see also: https://doc.dovecot.org/2.4.1/core/config/auth/passdb.html
#
$(echo -e "${NEW_BLOCK}")
EOF
fi
read -r -d '' NEW_BLOCK <<'EOF'
userdb sql {
# Load SQL connection data
!include /usr/local/dovecot-2.4.1-4/etc/dovecot/sql-connect.conf.ext
query = SELECT '/var/vmail/' || maildir AS home, \\
'5000' AS uid, '5000' AS gid \\
FROM mailbox \\
WHERE username = '%{user}' AND active = true
iterate_query = SELECT username AS user FROM mailbox
#iterate_query = SELECT userid AS username, domain FROM mailbox
}
EOF
if grep -qE "^\s*userdb sql\s+{" "${_conf_file}"; then
replace_code_block "userdb" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Dovecot uses passdb and userdb as part of the authentication process.
#
# passdb authenticated the user. userdb lookup then retrieves post-login information
# specific to the authenticated user. This may include:
#
# - Mailbox location information
# - Quota limit
# - Overriding settings for the user (almost any setting can be overridden)
#
#
# Userdb Lookups Dovecot Proxy Dovecot Backend
# ----------------------------------------------------------
# IMAP & POP3 logins No YES
# LMTP mail delivery No YES
# doveadm commands No YES
#
# The userdb and passdb may be the same or they may be different depending on your needs.
# You can also have multiple authentication databases.
#
# see: https://doc.dovecot.org/2.4.1/core/config/auth/userdb.html
#
$(echo -e "${NEW_BLOCK}")
EOF
fi
elif [[ "$db_driver" = "mysql" ]]; then
read -r -d '' NEW_BLOCK <<'EOF'
passdb sql {
# Load SQL connection data
!include /usr/local/dovecot-2.4.1-4/etc/dovecot/sql-connect.conf.ext
query = SELECT username AS user, password \\
FROM mailbox \\
WHERE username = '%{user}' AND active = true
}
EOF
if grep -qE "^\s*passdb\s+sql\s+{" "${_conf_file}"; then
replace_code_block "passdb sql" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Dovecot uses passdb and userdb as part of the authentication process.
#
# passdb authenticates the user. It also provides any other pre-login information
# needed for users, such as:
#
# - Which server user is proxied to.
# - If user should be allowed to log in at all (temporarily or permanently).
#
# Passdb Lookups Dovecot Proxy Dovecot Backend
# ----------------------------------------------------------
# IMAP & POP3 logins YES YES
# LMTP mail delivery YES YES
# doveadm commands YES YES
#
# see also: https://doc.dovecot.org/2.4.1/core/config/auth/passdb.html
#
$(echo -e "${NEW_BLOCK}")
EOF
fi
read -r -d '' NEW_BLOCK <<'EOF'
userdb sql {
# Load SQL connection data
!include /usr/local/dovecot-2.4.1-4/etc/dovecot/sql-connect.conf.ext
query = SELECT CONCAT('/var/vmail/',maildir) AS home, \\
'5000' AS uid, '5000' AS gid \\
FROM mailbox \\
WHERE username = '%{user}' AND active = true
iterate_query = SELECT username AS user FROM mailbox
#iterate_query = SELECT userid AS username, domain FROM mailbox
}
EOF
if grep -qE "^\s*userdb sql\s+{" "${_conf_file}"; then
replace_code_block "userdb" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Dovecot uses passdb and userdb as part of the authentication process.
#
# passdb authenticated the user. userdb lookup then retrieves post-login information
# specific to the authenticated user. This may include:
#
# - Mailbox location information
# - Quota limit
# - Overriding settings for the user (almost any setting can be overridden)
#
#
# Userdb Lookups Dovecot Proxy Dovecot Backend
# ----------------------------------------------------------
# IMAP & POP3 logins No YES
# LMTP mail delivery No YES
# doveadm commands No YES
#
# The userdb and passdb may be the same or they may be different depending on your needs.
# You can also have multiple authentication databases.
#
# see: https://doc.dovecot.org/2.4.1/core/config/auth/userdb.html
#
$(echo -e "${NEW_BLOCK}")
EOF
fi
fi # if [[ "$db_driver" = "pgsql" ]]; then
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/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 SQL auth '$(basename "${_conf_file}")'.."
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
#
_failed=false
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Create sql configuration file '$(basename "${_conf_file}")'.."
if [[ "$db_driver" = "pgsql" ]]; then
cat <<EOF > /usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf.ext 2> ${log_file}
##
## SQL Connection Parameter
##
passdb_default_password_scheme = ${default_pass_scheme}
sql_driver = pgsql
# ----------
# if using unix-socket (host=/run/postgresql) ensure that
# coresponding entries in pg_hba.cof fits
# for example
# local all all md5
#
# ----------
pgsql localhost {
parameters {
user=${dbuser}
password=${dbpassword}
dbname=${dbname}
}
}
EOF
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
elif [ "$db_driver" = "mysql" ]; then
cat <<EOF > /usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf.ext
##
## SQL Connection Parameter
##
passdb_default_password_scheme = ${default_pass_scheme}
sql_driver = mysql
mysql localhost {
parameters {
user=${dbuser}
password=${dbpassword}
dbname=${dbname}
}
}
EOF
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
fi # if [[ "$db_driver" = "pgsql" ]]; then
else
## - create sql configuration file
## -
echononl " Create sql configuration file '$(basename "${_conf_file}")'.."
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 = '%{user}' AND active = true
user_query = SELECT '/var/vmail/' || maildir AS home, \\
'5000' AS uid, '5000' AS gid \\
FROM mailbox \\
WHERE username = '%{user}' AND active = true
#WHERE username = substring ('%{user}' 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 = '%{user}' AND active = true
user_query = SELECT CONCAT('/var/vmail/',maildir) AS home, \\
'5000' AS uid, '5000' AS gid \\
FROM mailbox \\
WHERE username = '%{user}' 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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-logging.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-logging.conf
#
# 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 " Configure logging ($(basename "${_conf_file}")).."
if grep -qE "^\s*log_path\s*=" "${_conf_file}"; then
replace_variable "log_path" "syslog" "${_conf_file}" || _failed=true
else
cat <<'EOF' >> "${_conf_file}" || _failed=true
# Specify the log file to use for error messages.
#
# Options:
#
# - syslog: Log to syslog
# - /dev/stderr: Log to stderr
#
# If you don't want to use syslog, or if you just can't find the Dovecot's error logs,
# you can make Dovecot log elsewhere as well:
#
# log_path = /var/log/dovecot.log
#
# If you don't want errors, info, and debug logs all in one file, specify
# info_log_path or debug_log_path as well:
#
# log_path = /var/log/dovecot.log
# info_log_path = /var/log/dovecot-info.log
#
log_path = syslog
EOF
fi
if grep -qE "^\s*syslog_facility\s*=" "${_conf_file}"; then
replace_variable "syslog_facility" "local1" "${_conf_file}" || _failed=true
else
cat <<'EOF' >> "${_conf_file}" || _failed=true
# The syslog facility used if you're logging to syslog
syslog_facility = local1
EOF
fi
if grep -qE "^\s*auth_verbose\s*=" "${_conf_file}"; then
replace_variable "auth_verbose" "yes" "${_conf_file}" || _failed=true
else
cat <<'EOF' >> "${_conf_file}" || _failed=true
# If yes, log unsuccessful authentication attempts and why they failed.
auth_verbose = yes
EOF
fi
if grep -qE "^\s*auth_verbose_passwords\s*=" "${_conf_file}"; then
replace_variable "auth_verbose_passwords" "yes" "${_conf_file}" || _failed=true
else
cat <<'EOF' >> "${_conf_file}" || _failed=true
# In case of password mismatches, log the attempted password. You can also truncate
# the logged password to n chars by appending :n (e.g. sha1:6).
#
#Available transformations:
#
# plain, yes: Output cleartext password (NOT RECOMMENDED)
# sha1: Output SHA1 hashed password
auth_verbose_passwords = plain
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-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 " Configure logging ($(basename "${_conf_file}")).."
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(log_path\ ?=.*)#\1\#\# \2\n\1log_path = syslog#g" \
${_conf_file} || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(syslog_facility\ ?=.*)#\1\#\# \2\n\1syslog_facility = local1#g" \
${_conf_file} || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(auth_verbose\ ?=.*)#\1\#\# \2\n\1auth_verbose = yes#g" \
${_conf_file} || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(auth_verbose_passwords\ ?=.*)#\1\#\# \2\n\1auth_verbose_passwords = plain#g" \
${_conf_file} || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting ${_conf_file} 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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/15-lda.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/15-lda.conf
#
# postmaster_address = $postmaster_address
# hostname = $hostname
# sendmail_path = /usr/sbin/sendmail
# lda_mailbox_autocreate = no
#
# protocol lda {
# mail_plugins {
# sieve = yes
# quota = yes
# }
# }
#
echononl " Configure lda ($(basename "${_conf_file}")).."
if grep -qE "^\s*postmaster_address\s*=" "${_conf_file}"; then
replace_variable "postmaster_address" "${postmaster_address}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# The From address from which email rejection messages (bounces) are sent.
#
# Default postmaster@%{user|domain|default(hostname)}
#
# As used here, %{user | domain} expands to the domain of the local user. Other Mail user
# variables can be used as well.
# see: https://doc.dovecot.org/2.4.1/core/settings/variables.html#mail-user-variables
postmaster_address = ${postmaster_address}
EOF
fi
if grep -qE "^\s*hostname\s*=" "${_conf_file}"; then
replace_variable "hostname" "${hostname}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# The hostname to be used in email messages sent out by the local delivery agent
# (such as the Message-ID: header), in LMTP replies, and as the hostname advertised
# by submission SMTP service.
#
# Default: <system's real hostname@domain.tld>
hostname = ${hostname}
EOF
fi
if grep -qE "^\s*sendmail_path\s*=" "${_conf_file}"; then
replace_variable "sendmail_path" "/usr/sbin/sendmail" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# The binary to use for sending email.
#
#Used only if submission_host is not set.
sendmail_path = /usr/sbin/sendmail
EOF
fi
read -r -d '' NEW_BLOCK <<'EOF'
protocol lda {
mail_plugins {
sieve = yes
quota = yes
}
}
EOF
replace_or_append_code_block "protocol lda" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
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/15-lda.conf
## -
## - postmaster_address = $postmaster_address
## - hostname = $hostname
## - sendmail_path = /usr/sbin/sendmail
## - lda_mailbox_autocreate = no
## - mail_plugins = $mail_plugins sieve
## -
echononl " Configure lda ($(basename "${_conf_file}")).."
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(postmaster_address\ +=.*)#\1\#\# \2\n\1postmaster_address = $postmaster_address#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(hostname\ +=.*)#\1\#\# \2\n\1hostname = $hostname#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(sendmail_path\ +=.*)#\1\#\# \2\n\1sendmail_path = /usr/sbin/sendmail#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(lda_mailbox_autocreate\ +=.*)#\1\#\# \2\n\1lda_mailbox_autocreate = no#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = \\\$mail_plugins sieve#g" \
"${_conf_file}" || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting '${_conf_file}' 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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-lmtp.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/20-lmtp
#
# lmtp_save_to_detail_mailbox = no
#
# protocol lmtp {
# postmaster_address = $postmaster_address
# mail_plugins {
# sieve = yes
# quota = yes
# }
# }
#
: > "${log_file}"
echononl " Configure lmtp ($(basename "${_conf_file}")).."
if grep -qE "^\s*lmtp_save_to_detail_mailbox\s*=" "${_conf_file}"; then
replace_variable "lmtp_save_to_detail_mailbox" "no" "${_conf_file}" 2> "${log_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# If the recipient address includes a detail element / role (as in user+detail format),
# save the message to the detail mailbox.
lmtp_save_to_detail_mailbox = no
EOF
fi
postmaster_address="argus@oopen.de"
read -r -d '' NEW_BLOCK <<EOF
protocol lmtp {
# The From address from which email rejection messages (bounces) are sent.
#
# Default postmaster@%{user|domain|default(hostname)}
#
# As used here, %{user | domain} expands to the domain of the local user. Other Mail user
# variables can be used as well.
# see: https://doc.dovecot.org/2.4.1/core/settings/variables.html#mail-user-variables
postmaster_address = ${postmaster_address}
mail_plugins {
sieve = yes
quota = yes
}
}
EOF
replace_or_append_code_block "protocol lda" "${NEW_BLOCK}" "${_conf_file}" 2> "${log_file}" || _failed=true
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/20-lmtp
## -
## - lmtp_save_to_detail_mailbox = no
## - mail_plugins = $mail_plugins sieve
## -
echononl " Configure lmtp ($(basename "${_conf_file}")).."
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(lmtp_save_to_detail_mailbox\ +=.*)#\1\#\# \2\n\1lmtp_save_to_detail_mailbox = no#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = \\\$mail_plugins sieve#g" \
"${_conf_file}" || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting '${_conf_file}' failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/20-lmtp.conf
# edit /usr/local/dovecot/etc/dovecot/conf.d/20-imap.conf
#
_failed=false
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-imap.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/20-imap.conf
#
# imap_client_workarounds = delay-newmail
#
# protocol imap {
#
# mail_plugins = $mail_plugins imap_quota
# mail_max_userip_connections = $max_userip_connections
#
# ssl_client {
# cert_file = $imap_cert
# key_file = $imap_key
# }
#
# }
echononl " Configure imap protocol ($(basename "${_conf_file}")).."
if grep -qE "^\s*imap_client_workarounds\s*=" "${_conf_file}"; then
replace_variable "imap_client_workarounds" "delay-newmail" "${_conf_file}" 2>> "${log_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" 2>> "${log_file}" || _failed=true
# Workarounds for various IMAP client bugs can be enabled here.
#
# The following values are currently supported:
#
# delay-newmail
# EXISTS/RECENT new-mail notifications are sent only in replies to NOOP and CHECK
# commands. Some clients, such as pre-2.1 versions of Mac OS X Mail, ignore them
# otherwise, and, worse, Outlook Express may report that the message is no longer
# on the server (note that the workaround does not help for OE6 if synchronization
# is set to Headers Only).
# tb-extra-mailbox-sep
# Because mailbox_list_layout = fs (mbox and dbox) confuses Thunderbird, causing
# extra / suffixes to mailbox names, Dovecot can be told to ignore the superfluous
# character instead of judging the mailbox name to be invalid.
# tb-lsub-flags
# Without this workaround, Thunderbird doesn't immediately recognize that LSUB
# replies with mailbox_list_layout = fs aren't selectable, and users may receive
# pop-ups with not selectable errors. Showing \Noselect flags for these replies
# (e.g., in mbox use) causes them to be grayed out.
imap_client_workarounds = delay-newmail
EOF
fi
read -r -d '' NEW_BLOCK <<EOF
protocol imap {
# The maximum number of IMAP connections allowed for a user from each IP address.
#
# This setting is checked only by backends, not proxies.
#
# Note that for this to work, any username changes must be done already by
# passdb lookup (not by userdb lookup).
#
# Unique users are identified via case-sensitive comparison.
mail_max_userip_connections = $max_userip_connections
# A list of mail plugins to load.
mail_plugins {
acl = yes
quota = yes
imap_quota = yes
}
ssl_client {
cert_file = $imap_cert
key_file = $imap_key
}
}
EOF
replace_or_append_code_block "protocol imap" "${NEW_BLOCK}" "${_conf_file}" 2>> "${log_file}" || _failed=true
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/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 " Configure imap protocol ($(basename "${_conf_file}")).."
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" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_max_userip_connections\ +=.*)#\1\#\# \2\n\1mail_max_userip_connections = $max_userip_connections#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = \\\$mail_plugins imap_quota#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(imap_client_workarounds\ +=.*)#\1\#\# \2\n\1imap_client_workarounds = delay-newmail#g" \
"${_conf_file}" || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting '${_conf_file}' 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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-pop3.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Configure pop3 protocol ($(basename "${_conf_file}")).."
# edit /usr/local/dovecot/etc/dovecot/conf.d/20-pop3.conf
#
# pop3_client_workarounds = outlook-no-nuls oe-ns-eoh
#
# protocol pop3 {
# ssl_client {
# cert_file = $imap_cert
# key_file = $imap_key
# }
# }
if grep -qE "^\s*pop3_client_workarounds\s*=" "${_conf_file}"; then
replace_variable "pop3_client_workarounds" "outlook-no-nuls oe-ns-eoh" "${_conf_file}" 2>> "${log_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" 2>> "${log_file}" || _failed=true
# Workarounds for various POP3 client bugs can be enabled here.
#
# The following values are currently supported:
#
# oe-ns-eoh
# Because Outlook Express and Netscape Mail expect an end-of-headers line,
# this option sends one explicitly if none has been sent.
# outlook-no-nuls
# Because Outlook and Outlook Express hang if messages contain NUL characters,
# this setting replaces each of them with a 0x80 character.
pop3_client_workarounds = outlook-no-nuls oe-ns-eoh
EOF
fi
read -r -d '' NEW_BLOCK <<EOF
protocol pop3 {
# A list of mail plugins to load.
mail_plugins {
acl = yes
quota = yes
}
ssl_client {
cert_file = $pop_cert
key_file = $pop_key
}
}
EOF
replace_or_append_code_block "protocol pop3" "${NEW_BLOCK}" "${_conf_file}" 2>> "${log_file}" || _failed=true
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/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 " Configure pop3 protocol ($(basename "${_conf_file}")).."
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" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_max_userip_connections\ +=.*)#\1\#\# \2\n\1mail_max_userip_connections = 24#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(pop3_client_workarounds\ +=.*)#\1\#\# \2\n\1pop3_client_workarounds = outlook-no-nuls oe-ns-eoh#g" \
"${_conf_file}" || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting '${_conf_file}' 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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-plugin.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjusting expire plugin file '$(basename "${_conf_file}")'.."
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 expire plugin file '$(basename "${_conf_file}")'.."
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" \
"${_conf_file}" || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting '${_conf_file}' 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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-sieve.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjusting sieve configuration ($(basename "${_conf_file}")).."
if grep -qE "^\s*sieve_script\s+personal\s*{" "${_conf_file}"; then
read -r -d '' NEW_BLOCK <<EOF
sieve_script personal {
driver = file
path = ~/sieve
active_path = ~/.dovecot.sieve
}
EOF
replace_or_append_code_block "sieve_script personal" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
else
cat <<EOF >> "${_conf_file}" 2> "${log_file}"
# personal
# --------
#
# The personal storage serves as the user's main personal storage. Although more than a single
# personal storage can be defined, only the first one listed in the configuration is used.
#
# The LDA Sieve plugin uses the personal storage to find the active script for Sieve filtering
# at delivery. If the storage supports storing more than a single script (e.g. the file
# storage does), personal scripts can also be retrieved by name. The Sieve include extension
# will then use this storage for retrieving :personal scripts and the ManageSieve service will
# be able to store the user's scripts there.
#
# If the storage supports storing more than a single script, only one of those scripts will be
# the active script used at delivery. The active script can be managed by the user through the
# ManageSieve service. If the personal storage has no active script, the default script will
# be executed if configured.
#
# If no personal storage is defined explicitly, auto-detection will be attempted. This is
# currently only trying the [[link,sieve_storage_file,file storage driver], which looks for
# a ~/.dovecot.sieve script file or a directory at ~/sieve/ containing script files. In the
# latter case ~/.dovecot.sieve is expected to be a symbolic link pointing to the active script
# file. If auto-detection also finds no personal storage, Sieve processing will be skipped and
# no default script is executed.
sieve_script personal {
driver = file
path = ~/sieve
active_path = ~/.dovecot.sieve
}
EOF
if [[ $? -gt 0 ]]; then
_failed=true
fi
fi
if grep -qE "^\s*sieve_script\s+before\s*{" "${_conf_file}"; then
read -r -d '' NEW_BLOCK <<EOF
sieve_script before {
driver = file
path = /usr/local/dovecot/etc/dovecot/sieve/
}
EOF
replace_or_append_code_block "sieve_script before" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
else
cat <<EOF >> "${_conf_file}" 2> "${log_file}"
# after
# -----
#
# An after storage is the source of one script or several scripts that are to be executed after
# the user's personal script. If the storage supports storing more than a single script, these
# scripts will be executed in a well-defined order defined by the storage driver. Multiple after
# storages can be configured and each storage will be accessed in sequence to retrieve scripts
# for execution after the personal script. The storages will be accessed in the order these
# storages are defined in the configuration, unless the order is overridden by the
# sieve_script_precedence setting.
#
# This is usually a global script, so be sure to pre-compile the specified script manually in
# that case using the sievec command line tool, as explained by sievec(1).
#
# before
# ------
#
# A before storage behaves identical to an after storage, except the contained script or
# scripts are run before user's personal script (instead of after).
sieve_script before {
driver = file
path = /usr/local/dovecot/etc/dovecot/sieve/
}
EOF
if [[ $? -gt 0 ]]; then
_failed=true
fi
fi
if grep -qE "^\s*sieve_script\s+global\s*{" "${_conf_file}"; then
read -r -d '' NEW_BLOCK <<EOF
sieve_script global {
driver = file
path = /usr/local/dovecot/etc/dovecot/sieve/global/
}
EOF
replace_or_append_code_block "sieve_script global" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
else
cat <<EOF >> "${_conf_file}" 2> "${log_file}"
# default
# -------
#
# The default storage yields the sieve script that gets executed only if the user's personal
# Sieve script does not exist. Although more than a single default storage can be defined,
# only the first one listed in the configuration is used.
#
# If sieve_script_name is set for this script storage, the default script can be seen and
# accessed by this name through ManageSieve (and doveadm sieve). See below (Sieve visible
# default script).
#
# This is usually a global script, so be sure to pre-compile the specified script manually in
# that case using the sievec command line tool, as explained by sievec(1).
#
# discard
# -------
#
# The discard storage yields the sieve script that gets executed for any message that is about
# to be discarded; i.e., it is not delivered anywhere by the normal Sieve execution. Although
# more than a single discard storage can be defined, only the first one listed in the
# configuration is used. The discard storage is currently only applicable for message delivery.
#
# The script from the discard storage is only executed when the "implicit keep" is canceled,
# by e.g. the "discard" action, and no actions that deliver the message are executed. Delivery
# in this case means both local delivery to a mailbox and redirection to a remote recipient.
# This "discard script" can prevent discarding the message, by executing alternative actions.
# If the discard script does nothing, the message is still discarded as it would be when no
# scard script is configured.
#
# global
# -------
#
# A global storage is the source of :global include scripts for the Sieve include extension.
# Scripts are accessed by name, so if the storage yields only one script, a name must be
# defined for it; either implicitly by the storage driver or explicitly using sieve_script_name.
# Multiple global storages can be configured and each storage will be queried in sequence to
# retrieve the requested script by name. The storages will be queried in the order these
# storages are defined in the configuration until the script is found. The order can be
# overridden by the sieve_script_precedence setting.
sieve_script global {
driver = file
path = /usr/local/dovecot/etc/dovecot/sieve/global/
}
EOF
if [[ $? -gt 0 ]]; then
_failed=true
fi
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/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 sieve configuration ($(basename "${_conf_file}")).."
perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(sieve\ ?=.*)#\1\#\# \2\n\1sieve = ~/.dovecot.sieve#g" \
"${_conf_file}" || _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" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(sieve_dir\ ?=.*)#\1\#\# \2\n\1sieve_dir = ~/sieve#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(sieve_global\ ?=.*)#\1\#\# \2\n\1sieve_global = /usr/local/dovecot/etc/dovecot/sieve/global/#g" \
"${_conf_file}" || _failed=true
perl -i -n -p -e "s#^([ ]*)\#?\ ?(recipient_delimiter\ ?=.*)#\1\#\# \2\n\1recipient_delimiter =#g" \
"${_conf_file}" || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting "${_conf_file}""
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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/95-sieve-vacation.conf"
# edit /usr/local/dovecot/etc/dovecot/conf.d/95-sieve-vacation.conf
#
# sieve_extensions {
# vacation-seconds = yes
# }
#
# # One hour at minimum
# sieve_vacation_min_period = 1h
#
# # Ten days default
# sieve_vacation_default_period = 10d
#
# # Thirty days at maximum
# sieve_vacation_max_period = 30d
echononl " Add Setting for included Pigeonhole Sieve: Vacation Extension'.."
read -r -d '' NEW_BLOCK <<EOF
sieve_extensions {
vacation-seconds = yes
}
EOF
replace_or_append_code_block "sieve_extensions" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
fi
_replace_key="sieve_vacation_min_period"
_replace_val="1h"
read -r -d '' COMMENT_BLOCK <<EOF
# sieve_vacation_min_period
#
# Default 1d
# Value time
#
# Specifies the minimum period that can be specified for the :days and :seconds
# tags of the vacation command.
#
# A minimum of 0 indicates that users are allowed to make the Sieve interpreter send
# a vacation response message for every incoming message that meets the other reply
# criteria (refer to RFC 5230). A value of zero is not recommended.
EOF
if grep -qE "^\s*${_replace_key}\s*=" "${_conf_file}"; then
replace_variable "${_replace_key}" "${_replace_val}" "${_conf_file}" 2>> "${log_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" 2>> "${log_file}" || _failed=true
${COMMENT_BLOCK}
${_replace_key} = ${_replace_val}
EOF
fi
_replace_key="sieve_vacation_default_period"
_replace_val="10d"
read -r -d '' COMMENT_BLOCK <<EOF
# sieve_vacation_min_period
#
# Default 7d
# Value time
#
# Specifies the default period that is used when no :days or :seconds tag is specified.
#
# The configured value must lie between sieve_vacation_min_period and
# sieve_vacation_max_period.
EOF
if grep -qE "^\s*${_replace_key}\s*=" "${_conf_file}"; then
replace_variable "${_replace_key}" "${_replace_val}" "${_conf_file}" 2>> "${log_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" 2>> "${log_file}" || _failed=true
${COMMENT_BLOCK}
${_replace_key} = ${_replace_val}
EOF
fi
_replace_key="sieve_vacation_max_period"
_replace_val="60d"
read -r -d '' COMMENT_BLOCK <<EOF
# sieve_vacation_min_period
#
# Default 60d
# Value time
#
# Specifies the maximum period that can be specified for the :days tag of the
# vacation command.
#
# The configured value must be larger than sieve_vacation_min_period.
#
# A value of 0 has a special meaning: it indicates that there is no upper limit.
EOF
if grep -qE "^\s*${_replace_key}\s*=" "${_conf_file}"; then
replace_variable "${_replace_key}" "${_replace_val}" "${_conf_file}" 2>> "${log_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" 2>> "${log_file}" || _failed=true
${COMMENT_BLOCK}
${_replace_key} = ${_replace_val}
EOF
fi
_replace_key="sieve_vacation_send_from_recipient"
_replace_val="yes"
read -r -d '' COMMENT_BLOCK <<EOF
# sieve_vacation_min_period
#
# Default no
# Value 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.
EOF
if grep -qE "^\s*${_replace_key}\s*=" "${_conf_file}"; then
replace_variable "${_replace_key}" "${_replace_val}" "${_conf_file}" 2>> "${log_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" 2>> "${log_file}" || _failed=true
${COMMENT_BLOCK}
${_replace_key} = ${_replace_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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-sieve.conf"
# - Add Setting from Pigeonhole Sieve: Vacation Extension
# -
echononl " Add Setting for included Pigeonhole Sieve: Vacation Extension"
_found=false
_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 < "${_conf_file}"
cp -a "$_tmp_file" "${_conf_file}" > /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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Add lmtp to protocols ($(basename "${_conf_file}"))"
echo -e "${rc_skipped}"
else
echononl " Add lmtp to protocols ($(basename "${_conf_file}"))"
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
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
## - }
## -
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf"
echononl " Adding dovecot-lmtp listener to file $(basename "${_conf_file}")"
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"
# edit /usr/local/dovecot/etc/dovecot/conf.d/10-master.conf
#
# add service dict
#
_failed=false
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Configure dict service ($(basename "${_conf_file}"))"
echo -e "${rc_already_done}"
else
## - 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 ($(basename "${_conf_file}"))"
perl -i -n -p -e "s#^([ ]*)(unix_listener\ +dict.*)#\1\2\n\1 mode = 0600\n\1 user = vmail#g" \
"${_conf_file}" || _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
## - edit /usr/local/dovecot/etc/dovecot/dovecot.conf
## -
## - add:
## -
## - dict {
## - quota = $db_driver:/usr/local/dovecot/etc/dovecot/sql-dict.conf.ext
## - }
_failed=false
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Adjust file $(basename "${_conf_file}") for (dict) quota service"
echo -e "${rc_not_needed_anymore}"
else
echononl " Adjust file $(basename "${_conf_file}") 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" \
"${_conf_file}" || _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
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 # if new
# Renew file /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
#
_failed=false
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Renew SQL dict file '$(basename "${_conf_file}")'.."
echo -e "${rc_not_needed_anymore}"
info "Since version 2.4 we will use quota driver 'count'.
No dict service is needed for quota"
else
echononl " Renew SQL dict file '$(basename "${_conf_file}")'.."
if [ "$db_driver" = "pgsql" ]; then
cat <<EOF > "${_conf_file}"
## - 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 >> "${_conf_file}"
# 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
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 $plugin_expire
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
fi # Renew file /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
# In order to support extra variable "quota_rule", also userdb's and
# passdb's SQL query have to update
#
# Note:
# On versions 2.4.x and later, this happends in file'auth-sql.conf.ext'. On prior versions
# this happends in file 'sql-connect.conf.ext'
#
_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/auth-sql.conf.ext"
echononl " Renew SQL connect file '$(basename "${_conf_file}")'.."
if [[ "$db_driver" = "pgsql" ]]; then
read -r -d '' NEW_BLOCK <<'EOF'
userdb sql {
# Load SQL connection data
!include /usr/local/dovecot-2.4.1-4/etc/dovecot/sql-connect.conf.ext
query = SELECT '/var/vmail/' || maildir AS home, \\
'5000' AS uid, '5000' AS gid, \\
quota || 'B'AS quota_storage_size \\
FROM mailbox \\
WHERE username = '%{user}' AND active = true
iterate_query = SELECT username AS user FROM mailbox
#iterate_query = SELECT userid AS username, domain FROM mailbox
}
EOF
if grep -qE "^\s*userdb sql\s+{" "${_conf_file}"; then
replace_code_block "userdb sql" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Dovecot uses passdb and userdb as part of the authentication process.
#
# passdb authenticated the user. userdb lookup then retrieves post-login information
# specific to the authenticated user. This may include:
#
# - Mailbox location information
# - Quota limit
# - Overriding settings for the user (almost any setting can be overridden)
#
#
# Userdb Lookups Dovecot Proxy Dovecot Backend
# ----------------------------------------------------------
# IMAP & POP3 logins No YES
# LMTP mail delivery No YES
# doveadm commands No YES
#
# The userdb and passdb may be the same or they may be different depending on your needs.
# You can also have multiple authentication databases.
#
# see: https://doc.dovecot.org/2.4.1/core/config/auth/userdb.html
#
${NEW_BLOCK}
EOF
fi
if [[ $? -gt 0 ]]; then
_failed=true
fi
elif [[ "$db_driver" = "mysql" ]]; then
read -r -d '' NEW_BLOCK <<'EOF'
userdb sql {
# Load SQL connection data
!include /usr/local/dovecot-2.4.1-4/etc/dovecot/sql-connect.conf.ext
query = SELECT CONCAT('/var/vmail/',maildir) AS home, \
'5000' AS uid, '5000' AS gid, \
CONCAT(quota,'B') AS quota_storage_size \
FROM mailbox \
WHERE username = '%{user}' AND active = true
iterate_query = SELECT username AS user FROM mailbox
#iterate_query = SELECT userid AS username, domain FROM mailbox
}
EOF
if grep -qE "^\s*userdb sql\s+{" "${_conf_file}"; then
replace_code_block "userdb" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Dovecot uses passdb and userdb as part of the authentication process.
#
# passdb authenticated the user. userdb lookup then retrieves post-login information
# specific to the authenticated user. This may include:
#
# - Mailbox location information
# - Quota limit
# - Overriding settings for the user (almost any setting can be overridden)
#
#
# Userdb Lookups Dovecot Proxy Dovecot Backend
# ----------------------------------------------------------
# IMAP & POP3 logins No YES
# LMTP mail delivery No YES
# doveadm commands No YES
#
# The userdb and passdb may be the same or they may be different depending on your needs.
# You can also have multiple authentication databases.
#
# see: https://doc.dovecot.org/2.4.1/core/config/auth/userdb.html
#
$(echo -e "${NEW_BLOCK}")
EOF
fi
if [[ $? -gt 0 ]]; then
_failed=true
fi
fi # if [[ "$db_driver" = "pgsql" ]]; then
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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/sql-connect.conf.ext"
## - Update the userdb's query in file "/usr/local/dovecot/etc/dovecot/sql-connect.conf.ext"
## -
echononl " Renew SQL connect file '$(basename "${_conf_file}")'.."
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 = '%{user}' 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 = '%{user}' 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-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 = '%{user}' 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 = '%{user}' 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
fi # Update the userdb's and passdb's SQL query
# Renew file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf
#
# Configur service stats
#
_failed=false
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Add 'service stats' to file '$(basename "${_conf_file}")'.."
read -r -d '' NEW_BLOCK <<'EOF'
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
replace_or_append_code_block "service stats" "${NEW_BLOCK}" "${_conf_file}" >> "${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
## - configure stats service (10-master.conf)
## -
echononl " Add 'service stats' to file '$(basename "${_conf_file}")'.."
cat <<EOF >> "${_conf_file}"
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 ($(basename "${_conf_file}")) failed!"
else
echo -e "$rc_done"
fi
fi # Renew file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf
## - Add script 'post-login.sh'
## -
## - 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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Configure post-login service ($(basename "${_conf_file}")).."
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 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
replace_or_append_code_block "service post-login" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1
if [[ $? -gt 0 ]]; then
_failed=true
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
#
_failed=false
_conf_file="/usr/local/dovecot-${_version}/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 quota file '$(basename "${_conf_file}")'.."
_key="mailbox_list_index"
_val="yes"
if grep -qE "^\s*${_key}\s*=" "${_conf_file}"; then
replace_variable "${_key}" "${_val}" "${_conf_file}" || _failed=true
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.
${_key} = ${_val}
EOF
fi
read -r -d '' NEW_BLOCK <<'EOF'
protocol imap {
# Enable the IMAP QUOTA extension, allowing IMAP clients to ask for the
# current quota usage.
mail_plugins {
imap_quota = yes
}
}
EOF
replace_or_append_code_block "protocol imap" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
if [[ $? -gt 0 ]] ; then
_failed=true
fi
read -r -d '' NEW_BLOCK <<'EOF'
quota "User quota" {
# quota_storage_size
#
# Default unlimited
# Value unsigned integer
#
# See Also:
# quota_storage_extra
# quota_storage_percentage
# quota_message_count
# Quota Root
#
# Quota storage size limit for the Quota Root. This value is still
# multiplied by quota_storage_percentage and then increased by
# 'quota_storage_extra' to get the final value (in this mailbox or
# namespace). This is reported as the STORAGE limit in IMAP GETQUOTA
# commands. Using 0 as the value means the same as unlimited.
#quota_storage_size = 0
}
EOF
if grep -qE "^\s*quota \"User quota\"\s+{" "${_conf_file}"; then
replace_code_block 'quota "User quota"' "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Per-User Quota
# --------------
#
# You can override the quota settings in your userdb: Extra Fields. Keep global settings
# from below in configuration plugin section and override only those settings you need
# to in your userdb.
#
# Use doveadm user command to verify that the userdb returns the expected quota settings.
$(echo -e "${NEW_BLOCK}")
EOF
fi
if [[ $? -gt 0 ]] ; then
_failed=true
fi
read -r -d '' NEW_BLOCK <<'EOF'
protocol !indexer-worker {
mail_vsize_bg_after_count = 100
}
EOF
if grep -qE "^\s*protocol \!indexer-worker\s+{" "${_conf_file}"; then
replace_code_block 'protocol !indexer-worker' "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Avoid spending excessive time waiting for the quota calculation to finish
# when mails' vsizes aren't already cached. If this many mails are opened,
# finish the quota calculation on background in indexer-worker process. Mail
# deliveries will be assumed to succeed, and explicit quota lookups will
# return internal error.
$(echo -e "${NEW_BLOCK}")
EOF
fi
if [[ $? -gt 0 ]] ; then
_failed=true
fi
read -r -d '' NEW_BLOCK <<'EOF'
quota user {
warning warn-95 {
quota_storage_percentage = 95
execute quota-warning {
args = 95 %{user}
}
}
warning warn-80 {
quota_storage_percentage = 80
execute quota-warning {
args = 80 %{user}
}
}
warning warn-under {
quota_storage_percentage = 100
# user is no longer over quota
threshold = under
execute quota-warn-under {
args = 100 %{user}
}
}
}
EOF
if grep -qE "^\s*quota\s+user\s+{" "${_conf_file}"; then
replace_code_block "quota user" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Then user's quota exceeds 80% quota-warning.sh is executed with parameter 80.
# The same goes for when quota exceeds 95%. If user suddenly receives a huge
# mail and the quota jumps from 70% to 99%, only the 95 script is executed.
$(echo -e "${NEW_BLOCK}")
EOF
fi
if [[ $? -gt 0 ]] ; then
_failed=true
fi
read -r -d '' NEW_BLOCK <<'EOF'
namespace inbox {
mailbox Trash {
quota_storage_extra = 100M
}
mailbox Spam {
quota_ignore = yes
}
}
EOF
replace_or_append_code_block "namespace inbox" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
if [[ $? -gt 0 ]] ; then
_failed=true
fi
read -r -d '' NEW_BLOCK <<'EOF'
service quota-warning {
executable = script /usr/local/bin/quota-warning.sh
# use some unprivileged user for executing the quota warnings
user = vmail
unix_listener quota-warning {
user = vmail
mode = 0666
}
}
EOF
replace_or_append_code_block "service quota-warning" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
read -r -d '' NEW_BLOCK <<'EOF'
service quota-warn-under {
executable = script /usr/local/bin/quota-warn-under.sh
# use some unprivileged user for executing the quota warn-under script
user = vmail
unix_listener quota-warn-under {
user = vmail
mode = 0666
}
}
EOF
replace_or_append_code_block "service quota-warn-under" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
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/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 quota file '$(basename "${_conf_file}")'"
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 [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); 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/dovecot-lda -d \${user} -o quota_enforce=no
Date: \`date +"%a, %e %b %Y %H:%M:%S %z"\`
From: $from_address
Reply-to: $reply_to
To:\${user}
Subject: mailbox quota warning: mehr \${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
Achte darauf nach dem Löschen gegebenenfalls auch den Papierkorb zu leeren.
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
echononl " Create quota warn-under script.."
## - create the user-warning script
## -
cat <<EOF >/usr/local/bin/quota-warn-under.sh
#!/usr/bin/env bash
percent=\$1
user=\$2
cat << EOF | /usr/local/dovecot/libexec/dovecot/dovecot-lda -d \${user} -o quota_enforce=no
Date: \`date +"%a, %e %b %Y %H:%M:%S %z"\`
From: $from_address
Reply-to: $reply_to
To:\${user}
Subject: mailbox quota: Weniger als \${percent}% belegt.
content-type: text/plain;
charset=utf-8
Hallo!
Deine Mailbox
\${user}
kann nun wieder E-MAIL empfangen.
Beachte, dass, je nach dem wieviel Platz du frei gemacht hast, dein verfügbarer Speicher auch schnell wieder vollständig belegt sein kann.
Du kannst den aktuellen Füllstand in deinem Mailprogramm oder im Webmailer hier einsehen:
$webmailer
Viele Grüße
$salutation
${_EOF:-EOF}
EOF
if [ "$?" = 0 ]; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Create quota warn-under script /usr/local/bin/quota-warn-under.sh failed"
fi
chmod 755 /usr/local/bin/quota-warn-under.sh
else
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}% belegt. 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
echo
echo -e "\033[1mConfigure ACL support for dovecot\033[m"
## - 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/20-imap.conf
#
# mail_plugins = $mail_plugins imap_quota imap_acl
#
_failed=false
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-imap.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Add mail_plugin imap_acl to file '$(basename "${_conf_file}")'.."
read -r -d '' NEW_BLOCK <<EOF
protocol imap {
# The maximum number of IMAP connections allowed for a user from each IP address.
#
# This setting is checked only by backends, not proxies.
#
# Note that for this to work, any username changes must be done already by
# passdb lookup (not by userdb lookup).
#
# Unique users are identified via case-sensitive comparison.
mail_max_userip_connections = $max_userip_connections
# A list of mail plugins to load.
mail_plugins {
imap_acl = yes
imap_quota = yes
}
ssl_client {
cert_file = $imap_cert
key_file = $imap_key
}
}
EOF
replace_or_append_code_block "protocol imap" "${NEW_BLOCK}" "${_conf_file}" 2>> "${log_file}" || _failed=true
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/20-imap.conf
## -
## - mail_plugins = $mail_plugins imap_quota imap_acl
## -
echononl " Add mail_plugin imap_acl to file '$(basename "${_conf_file}")'"
perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = \\\$mail_plugins imap_quota imap_acl#g" \
"${_conf_file}" || _failed=true
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
fatal "Adjusting file '${_conf_file}' failed"
fi
fi # edit /usr/local/dovecot/etc/dovecot/conf.d/20-imap.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
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-acl.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Configure acl - file '$(basename "${_conf_file}")'.."
read -r -d '' NEW_BLOCK <<'EOF'
protocol imap {
mail_plugins {
imap_acl = yes
}
}
EOF
if grep -qE "^\s*protocol imap\s+{" "${_conf_file}"; then
replace_code_block "protocol imap" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Enable the IMAP ACL commands
${NEW_BLOCK}
EOF
fi
if grep -qE "^\s*acl_driver\s+=" "${_conf_file}"; then
replace_variable "acl_driver" "vfile" "${_conf_file}" 2>> "${log_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# The ACL driver to use. This setting is REQUIRED - if empty, the
# acl plugin is disabled.
#
# Currently, there is a single driver available: vfile. This driver supports
# two ways of defining the ACL configuration:
#
# - global: ACL rules are applied to all users.
#
# - per-mailbox: Each mailbox has separate ACL rules. They are stored in a
# dovecot-acl file in each mailbox (or mail_control_path) directory. This
# is the default.
acl_driver = vfile
EOF
fi
read -r -d '' NEW_BLOCK <<'EOF'
namespace shared {
type = shared
separator = /
# Mailboxes are visible under "shared/user@domain/"
#
# Changed: 2.4.0 The shared namespaces now use $user,
# $username and $domain template variables, rather than
# the old %%u, %%n and %%d.
prefix = shared/$user/
# Mail location setting
mail_driver = maildir
mail_path = %{owner_home}/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
if grep -qE "^\s*namespace\s+shared\s+{" "${_conf_file}"; then
replace_code_block "namespace shared" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# This creates a shared/ namespace under which each user's mailboxes are.
${NEW_BLOCK}
EOF
fi
read -r -d '' NEW_BLOCK <<'EOF'
acl_sharing_map {
dict file {
path = /var/vmail/shared-mailboxes.db
}
}
EOF
if grep -qE "^\s*acl_sharing_map\s+{" "${_conf_file}"; then
replace_code_block "acl_sharing_map" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# A shared mailbox dictionary that defines which users may LIST mailboxes shared by other users.
${NEW_BLOCK}
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/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 file '$(basename "${_conf_file}")'"
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
# Renew file /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext
#
_failed=false
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Renew SQL dict file '$(basename "${_conf_file}")'.."
echo -e "$rc_not_needed_anymore"
else
echononl " Renew SQL dict file '$(basename "${_conf_file}")'.."
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
fi
## -
## - End: Using SQL dictionary
## ------------------------------------------------------------------------
## -----------------
## --- Configure managesieve support for dovecot
# edit /usr/local/dovecot/etc/dovecot/conf.d/20-managesieve.conf
#
_failed=false
_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-managesieve.conf"
if [[ $dovecot_major_version -gt 2 ]] \
|| ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then
echononl " Configure managesieve '$(basename "${_conf_file}")'.."
read -r -d '' NEW_BLOCK <<EOF
service managesieve-login {
inet_listener sieve {
#listen = 127.0.0.1 $ipv4 $ipv6
listen = 127.0.0.1
port = 4190
}
#inet_listener sieve_deprecated {
# port = 2000
#}
# Number of connections to handle before starting a new process. Typically
# the only useful values are "unlimited" or 1. 1 is more secure, but
# "unlimited" is faster.
#restart_request_count = 1
# Number of processes to always keep waiting for more connections.
#process_min_avail = 0
}
EOF
replace_or_append_code_block "service managesieve-login" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
read -r -d '' NEW_BLOCK <<EOF
service managesieve {
# Max. number of ManageSieve processes (connections)
#process_limit = 1024
}
EOF
replace_or_append_code_block "service managesieve" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
read -r -d '' NEW_BLOCK <<EOF
protocol sieve {
# Maximum ManageSieve command line length in bytes. ManageSieve usually does
# not involve overly long command lines, so this setting will not normally
# need adjustment
#managesieve_max_line_length = 65536
# Maximum number of ManageSieve connections allowed for a user from each
# IP address.
# NOTE: The username is compared case-sensitively.
#mail_max_userip_connections = 10
# List of plugins to load (none known to be useful so far).
# Do NOT try to load IMAP plugins here.
#mail_plugins {
#}
# MANAGESIEVE logout format string:
# %i - total number of bytes read from client
# %o - total number of bytes sent to client
#managesieve_logout_format = bytes=%i/%o
# To fool ManageSieve clients that are focused on CMU's timesieved you can
# specify the IMPLEMENTATION capability that the dovecot reports to clients.
# For example: 'Cyrus timsieved v2.2.13'
#managesieve_implementation_string = Dovecot Pigeonhole
# Explicitly specify the SIEVE and NOTIFY capability reported by the server
# before login. If left unassigned these will be reported dynamically
# according to what the Sieve interpreter supports by default (after login
# this may differ depending on the user).
#managesieve_sieve_capability =
#managesieve_notify_capability =
# The maximum number of compile errors that are returned to the client
# upon script upload or script verification.
#managesieve_max_compile_errors = 5
}
EOF
replace_or_append_code_block "protocol sieve" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
read -r -d '' NEW_BLOCK <<'EOF'
sieve_script personal {
path = ~/sieve
active_path = ~/.dovecot.sieve
}
EOF
if grep -qE "^\s*sieve_script\s+personal\s+{" "${_conf_file}"; then
replace_code_block "sieve_script personal" "${NEW_BLOCK}" "${_conf_file}" || _failed=true
else
cat <<EOF >> "${_conf_file}" || _failed=true
# Used by both the Sieve plugin and the ManageSieve protocol
${NEW_BLOCK}
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/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
blank_line
_mode=644
_owner="root"
_group="staff"
echononl " Set owner/group permissions all configuration files to 'root:staff'."
find "/usr/local/dovecot-${_version}/etc/dovecot" -type f -exec chown "${_owner}:${_group}" {} +
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Setting the owner and group for the configuration files failed!"
fi
echononl " Set permissions for all configuration files to '644'."
find "/usr/local/dovecot-${_version}/etc/dovecot" -type f -exec chmod "${_mode}" {} +
if ! $_failed ; then
echo -e "$rc_done"
else
echo -e "$rc_failed"
error "Setting permissions on configuration files failed!"
fi
blank_line
## - 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