#!/usr/bin/env bash ## =================================================================== ## - Install/Update Dovecot Server ## =================================================================== ## ----------------------------------------------------------------- ## ---------------------------------------------------------------- ## --- ## --- For configurations see file conf/install_update_dovecot.conf ## --- ## --- Dont make changes here! ## --- ## ----------------------------------------------------------------- ## ----------------------------------------------------------------- # ------------- # - Settings # ------------- _src_base_dir="$(realpath $(dirname $0))" conf_file="${_src_base_dir}/conf/install_update_dovecot.conf" curdir=`pwd` log_file="$(mktemp)" backup_date="$(date +%Y-%m-%d-%H%M)" _backup_crontab_file="/tmp/crontab_root.${backup_date}" rc_done="\033[71G[ \033[32mdone\033[m ]" rc_failed="\033[71G[ \033[31m\033[1mfailed\033[m ]" #rc_skipped="\033[71G[ \033[33m\033[1mskipped\033[m ]" rc_skipped="\033[71G[ \033[1;37mskipped\033[m ]" rc_wait="\033[71G[ \033[5m\033[1m..\033[m ]" rc_not_yet_implemented="\033[71G[ \033[1;33mNot Yet Implemented\033[m ]" # ------------- # - Functions an Variable # ------------- clean_up() { if [[ -f "$_backup_crontab_file" ]]; then echononl "(Re)Install previously saved crontab from '$_backup_crontab_file'.." crontab $_backup_crontab_file >> $log_file 2>&1 if [[ $? -eq 0 ]]; then echo -e "$rc_done" else echo -e "$rc_failed" error "$(cat $log_file)" fi fi # Perform program exit housekeeping rm -f $log_file blank_line exit $1 } echononl(){ echo X\\c > /tmp/shprompt$$ if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then echo -e "$*\\c" 1>&2 else echo -en "$*" 1>&2 fi rm /tmp/shprompt$$ } fatal(){ echo "" echo -e "\t[ \033[31m\033[1mFatal\033[m ]: \033[37m\033[1m$*\033[m" echo "" echo -e "\t\033[31m\033[1m Skript wird abgebrochen\033[m\033[m\n" rm -f $log_file clean_up 1 } error(){ echo "" echo -e "\t[ \033[31m\033[1mError\033[m ]: $*" echo "" } warn(){ echo "" echo -e "\t[ \033[33m\033[1mWarning\033[m ]: $*" echo "" } info(){ echo "" echo -e "\t[ \033[32m\033[1mInfo\033[m ]: $*" echo "" } blank_line() { echo "" } echo_ok() { echo -e "\033[71G[ \033[32mok\033[m ]" } echo_failed(){ echo -e "\033[71G[ \033[1;31mfailed\033[m ]" } echo_skipped() { echo -e "\033[71G[ \033[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 $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 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 " 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 < ${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) ## - 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" echo " -u root -S /run/mysqld/mysqld.sock" echo " --login-path=local" echo " --defaults-file=/usr/local/mysql/sys-maint.cnf" echo " --defaults-file=/etc/mysql/debian.cnf" echo " ..." echo "" echo -e " Type \"\033[33mNone\033[m\" if no credentials are needed for root user (MariaDB)" echo "" MYSQL_CREDENTIALS="" if [[ -n "${DEFAULT_MYSQL_CREDENTIALS}" ]] ; then while [[ -z "${MYSQL_CREDENTIALS}" ]] ; do echononl "MySQL credentials [${DEFAULT_MYSQL_CREDENTIALS}]: " read MYSQL_CREDENTIALS if [[ -z "${MYSQL_CREDENTIALS}" ]] ;then MYSQL_CREDENTIALS="${DEFAULT_MYSQL_CREDENTIALS}" fi done else while [[ -z "${MYSQL_CREDENTIALS}" ]] ; do echononl "MySQL credentials: " read MYSQL_CREDENTIALS if "${MYSQL_CREDENTIALS}" ]] ; then echo -e "\n\t\033[33m\033[1mMySQL credentials are required (or type\033[33mNone\033[m) : " continue fi if [[ "$(trim ${MYSQL_CREDENTIALS,,})" = 'none' ]] ; then MYSQL_CREDENTIALS="" break fi done fi echo "" echo "--" echo "" echo "" if [[ "${MYSQL_CREDENTIALS}" != "${DEFAULT_MYSQL_CREDENTIALS}" ]] ; then echo "MYSQL_CREDENTIALS=\"${MYSQL_CREDENTIALS}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE} fi fi fi export PGPASSWORD=$dbpassword echo -e "\033[1mDoing some backups\033[m.." echononl " Backup existing installation log directory.." if [[ -d "${_log_dir}" ]]; then mv "${_log_dir}" "${_log_dir}.${backup_date}" if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" error "Cannot Backup (move) directory '${_log_dir}'" fi else echo -e "$rc_skipped" fi echononl " Backup existing installation directory.." if [[ -d "/usr/local/dovecot-${_version}" ]]; then mv "/usr/local/dovecot-${_version}" "/usr/local/dovecot-${_version}.${backup_date}" if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" error "Cannot Backup (move) directory '${_log_dir}'" echononl "Proceed instllation [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" fi else echo -e "$rc_skipped" fi echononl " Backup existing source directory.." if [[ -d "${_src_base_dir}/dovecot-${_version}" ]]; then mv "${_src_base_dir}/dovecot-${_version}" "${_src_base_dir}/dovecot-${_version}.${backup_date}" if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" error "Cannot Backup (move) directory '${_src_base_dir}/dovecot-${_version}'" echononl "Proceed instllation [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" fi else echo -e "$rc_skipped" fi mkdir -p $_log_dir ## ----------------- ## --- Download cd ${_src_base_dir} echo "" echo -e "\033[1mDownload sources\033[m.." ## - Downloud Dovecot 2.2.x ## - echononl " Download dovecot-${_version}.tar.gz" if [ ! -f "${_src_base_dir}/dovecot-${_version}.tar.gz" ]; then wget --no-check-certificate https://dovecot.org/releases/${dovecot_main_version}/dovecot-${_version}.tar.gz > /dev/null 2>&1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" error "Direct download of 'dovecot-${_version}.tar.gz' failed Download \033[1mdovecot-${_version}.tar.gz\033[m manually and proceed instllation." echononl "Proceed instllation [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" fi else echo -e "$rc_skipped" fi ## - Download Pigeonhole for Dovecot v2.2 ## - if [[ ${dovecot_major_version} -eq 2 ]] && [[ ${dovecot_minor_version} -lt 4 ]] ; then echononl " Download dovecot-${dovecot_main_version}-pigeonhole-${_pigeonhole}.tar.gz.." if [ ! -f "${_src_base_dir}/dovecot-${dovecot_main_version}-pigeonhole-${_pigeonhole}.tar.gz" ]; then wget --no-check-certificate https://pigeonhole.dovecot.org/releases/${dovecot_main_version}/dovecot-${dovecot_main_version}-pigeonhole-${_pigeonhole}.tar.gz > /dev/null 2>&1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" error "Direct download of 'dovecot-${dovecot_main_version}-pigeonhole-${_pigeonhole}.tar.gz' failed Download \033[1mdovecot-${dovecot_main_version}-pigeonhole-${_pigeonhole}.tar.gz\033[m manually and proceed instllation." echononl " Proceed instllation [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" fi else echo -e "$rc_skipped" fi dovecot_pigeonhole_archiv="dovecot-${dovecot_main_version}-pigeonhole-${_pigeonhole}.tar.gz" else echononl " Download dovecot-pigeonhole-${_pigeonhole}.tar.gz.." if [ ! -f "${_src_base_dir}/dovecot-pigeonhole-${_pigeonhole}.tar.gz" ]; then wget --no-check-certificate https://pigeonhole.dovecot.org/releases/${dovecot_main_version}/dovecot-pigeonhole-${_pigeonhole}.tar.gz > /dev/null 2>&1 if [ "$?" = 0 ]; then echo -e "$rc_done" dovecot_pigeonhole_archiv="dovecot-pigeonhole-${_pigeonhole}.tar.gz" else echo -e "$rc_failed" error "Direct download of 'Pigeonhole Sieve and ManageSieve' source archiv failed Download Pigeonhole Sieve and ManageSieve manually and name it to \033[1mdovecot-pigeonhole-${_pigeonhole}.tar.gz\033[m\n" echononl " Proceed instllation [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" fi else echo -e "$rc_skipped" fi dovecot_pigeonhole_archiv="dovecot-pigeonhole-${_pigeonhole}.tar.gz" fi dovecot_pigeonhole_archiv_prefix="${dovecot_pigeonhole_archiv%.tar.gz}" dovecot_pigeonhole_archiv_dir="${dovecot_pigeonhole_archiv%.tar.gz}" if $_new ; then ## - Install reqired debian packages ## - echo "" echo -e "\033[1mInstalling required debian packages\033[m.." echononl " Installing libpq5 libpq-dev .." if ! dpkg -l libpq-dev | grep -e "^ii" | grep libpq-dev > /dev/null ; then apt-get install libpq5 libpq-dev > ${_log_dir}/debian-install.log 2&>1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal "installing debian package(s) failed" fi else echo -e "$rc_skipped" fi echononl " Installing libkrb5-dev .." if ! dpkg -l libkrb5-dev | grep -e "^ii" | grep libkrb5-dev > /dev/null ; then apt-get install libkrb5-dev >> ${_log_dir}/debian-install.log 2&>1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal "installing debian package(s) failed" fi else echo -e "$rc_skipped" fi fi ## ----------------- ## - Create Users/groups needed for dovecot echo "" echo -e "\033[1mCreate required users/groups\033[m.." echononl " Create group dovecot.." if ! grep dovecot /etc/group > /dev/null ; then addgroup --system --gid 91 dovecot > ${_log_dir}/system.log 2>&1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal Create group failed fi else echo -e "$rc_skipped" fi echononl " Create user dovecot.." if ! grep dovecot /etc/passwd > /dev/null ; then adduser --system --home /var/empty --no-create-home --shell /usr/sbin/nologin \ --ingroup dovecot --uid 91 dovecot > ${_log_dir}/system.log 2>&1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal Create user failed fi else echo -e "$rc_skipped" fi echononl " Add Apache User (${http_user}) to group 'dovecot'.." if getent group dovecot 2> /dev/null | grep -q "\b${http_user}\b" > /dev/null 2>&1 ; then echo -e "$rc_skipped" else usermod -a -G dovecot $http_user > ${_log_dir}/system.log 2>&1 if [[ $? -eq 0 ]] ; then echo -e "$rc_done" else echo -e "$rc_failed" error "Failed to add Apache User (${http_user}) to group 'dovecot'!" fi fi echononl " Create group dovenull.." if ! grep dovenull /etc/group > /dev/null ; then addgroup --system --gid 65533 dovenull > ${_log_dir}/system.log 2>&1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal Create group failed fi else echo -e "$rc_skipped" fi echononl " Create user dovenull.." if ! grep dovenull /etc/passwd > /dev/null ; then adduser --system --home /var/empty --no-create-home --shell /usr/sbin/nologin \ --ingroup dovenull --uid 65533 dovenull > ${_log_dir}/system.log 2>&1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal Create user failed fi else echo -e "$rc_skipped" fi if $update ; then # - Deaktiviere Cronjobs # - echo "" echononl " Backup Crontab (user toot) to '$_backup_crontab_file'" crontab -l > $_backup_crontab_file 2> $log_file if [[ $? -eq 0 ]]; then echo -e "$rc_done" else echo -e "$rc_failed" error "Backup Crontab to '$_backup_crontab_file' failed" # If no crontab was present, the backup file contains # th string "no crontab fo root". Better to delete the # backup crontab file.. # rm -f $_backup_crontab_file fi echononl " Remove crontab for user root.." crontab -r > $log_file 2>&1 if [[ $? -eq 0 ]]; then echo -e "$rc_done" else echo -e "$rc_failed" error "" fi fi ## ----------------- ## --- Install Base System echo "" echo -e "\033[1mInstalling Base System\033[m.." ## - Unpack dovecot sources ## - cd ${_src_base_dir} echononl " Unpack dovecot-${_version}.tar.gz.." tar -xzf dovecot-${_version}.tar.gz > /dev/null if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal Extracting dovecot failed fi cd dovecot-${_version} ## - Configure dovecot ## - config_params=" --prefix=/usr/local/dovecot-${_version} \ --with-${db_driver} \ --with-gssapi=yes --with-ldap=yes --with-rundir=/run/dovecot" if $systemd_support ; then config_params="$config_params \ --with-systemd" fi #--with-systemdsystemunitdir=/etc/systemd/system/" echononl " Configure Dovecot.." #./configure \ # --prefix=/usr/local/dovecot-${_version} \ # --with-${db_driver} \ # --with-gssapi=yes > ${_log_dir}/dovecot-${_version}-configure.log 2>&1 #--with-systemdsystemunitdir=/etc/systemd/system \ LDFLAGS="-s" \ ./configure $config_params > ${_log_dir}/dovecot-${_version}-configure.log 2>&1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal Configuring dovecot failed fi ## - Compile dovecot ## - echononl " Compile Dovecot Sources.." make > ${_log_dir}/dovecot-${_version}-make.log 2>&1 || clean_up 1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal Compiling dovecot failed fi ## ----------------- ## --- Stop dovecot if running echononl " Stop dovecot service.." if ps ax 2> /dev/null | grep -q -E "/usr/local/dovecot[0-9.-]*/sbin/dovecot" > /dev/null 2>&1 ; then if $systemd_support ; then systemctl stop dovecot > /dev/null 2>&1 else /etc/init.d/dovecot stop > /dev/null 2>&1 fi if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" error "Stopping dovecot service failed" fi else echo -e "$rc_skipped" fi blank_line echononl " Remove dovecot service file if exists.." if [[ -f "/etc/systemd/system/dovecot.service" ]] ; then rm -f "/etc/systemd/system/dovecot.service" > /dev/null 2>&1 if [[ "$?" -gt 0 ]]; then echo -e "$rc_failed" error "Removing file '/etc/systemd/system/dovecot.service' failed." else echo -e "$rc_done" fi else echo -e "$rc_skipped" fi echononl " Remove dovecot systemd's socket file if exists.." if [[ -f "/etc/systemd/system/dovecot.socket" ]] ; then rm -f "/etc/systemd/system/dovecot.socket" > /dev/null 2>&1 if [[ "$?" -gt 0 ]]; then echo -e "$rc_failed" error "Removing systemd's socket file '/etc/systemd/system/dovecot.socket' failed." else echo -e "$rc_done" fi else echo -e "$rc_skipped" fi echononl " Remove directory '/etc/systemd/system/dovecot.service.d' if exists.." if [[ -d "/etc/systemd/system/dovecot.service.d" ]] ; then rm -rf "/etc/systemd/system/dovecot.service.d" > /dev/null 2>&1 if [[ "$?" -gt 0 ]]; then echo -e "$rc_failed" error "Removing directory '/etc/systemd/system/dovecot.service.d' failed." else echo -e "$rc_done" fi else echo -e "$rc_skipped" fi blank_line ## - Install dovecot ## - echononl " Install Dovecot into Folder /usr/local/dovecot-${_version}" make install > ${_log_dir}/dovecot-${_version}-install.log 2>&1 || clean_up 1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal Installing dovecot failed fi blank_line if [[ $dovecot_major_version -gt 2 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then echononl " Create Configuration Directory 'etc/dovecot/conf.d'.." if [[ ! -d "/usr/local/dovecot-${_version}/etc/dovecot/conf.d" ]] ; then mkdir -p "/usr/local/dovecot-${_version}/etc/dovecot/conf.d" > $log_file 2>&1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" error "$(cat $log_file)" echononl " continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" fi else echo -e "$rc_skipped" fi _conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf" echononl " Create empty file '$(basename "${_conf_file}")'.." if [[ ! -f "${_conf_file}" ]] ; then _failed=false touch "${_conf_file}" > ${log_file} if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" error "Creating empty file '${_conf_file}' failed!" fi else echo -e "$rc_skipped" fi _conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf" echononl " Create empty file '$(basename "${_conf_file}")'.." if [[ ! -f "${_conf_file}" ]] ; then 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 blank_line fi ## - Add /usr/local/dovecot/bin to PATH variable ## - ## - Edit /etc/profile and add bevor "export PATH" directive: ## - ## - checkdir="/usr/local/dovecot/bin" ## - if [ -d $checkdir ]; then ## - PATH=$PATH:$checkdir ## - fi ## - echononl " Add /usr/local/dovecot/bin to PATH variable.." if ! grep "checkdir=\"/usr/local/dovecot/bin\"" /etc/profile > /dev/null ; then perl -i -n -p -e "s#^(\s*)(export\ +PATH)#checkdir=\"/usr/local/dovecot/bin\"\nif [ -d \\\$checkdir ]; then\n PATH=\\\$PATH:\\\$checkdir\nfi\n\n\1\2#" /etc/profile if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal Adjusting /etc/profile failed fi else echo -e "$rc_skipped" fi echononl " Copy Manpages if not exists.." ## - Manpages ## - if ! grep /usr/local/dovecot/share/man /etc/manpath.config > /dev/null 2<&1 ; then echo >> /etc/manpath.config echo "MANDATORY_MANPATH /usr/local/dovecot/share/man /var/cache/man" >> /etc/manpath.config echo "MANPATH_MAP /usr/local/dovecot/bin /usr/local/dovecot/share/man" >> /etc/manpath.config echo "MANDB_MAP /usr/local/dovecot/share/man /var/cache/man" >> /etc/manpath.config echo -e "$rc_done" else echo -e "$rc_skipped" fi ## ----------------- ## --- Install Pigeonhole ManageSieve cd ${_src_base_dir} echo "" echononl " Extracting ${dovecot_pigeonhole_archiv}.." gunzip < ${_src_base_dir}/${dovecot_pigeonhole_archiv} | tar -C ${_src_base_dir} -xf - if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal Extracting '${dovecot_pigeonhole_archiv}' failed fi cd ${dovecot_pigeonhole_archiv_dir} echononl " Configure Pigeonhole ManageSieve.." ./configure \ --prefix=/usr/local/dovecot-${_version} \ --with-dovecot=/usr/local/dovecot-${_version}/lib/dovecot > ${_log_dir}/${dovecot_pigeonhole_archiv_prefix}-configure.log 2<&1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal Configuring Pigeonhole ManageSieve failed fi echononl " Compile Pigeonhole ManageSieve.." make > ${_log_dir}/${dovecot_pigeonhole_archiv_prefix}-make.log 2<&1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal Compiling Pigeonhole ManageSieve failed fi echononl " Install Pigeonhole ManageSieve.." make install > ${_log_dir}/${dovecot_pigeonhole_archiv_prefix}-install.log 2<&1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" fatal Installing Pigeonhole ManageSieve failed fi ## ----------------- ## --- Configure dovecot services #echo "" #echo -e "\033[1mConfigure Dovecot\033[m.." blank_line ## - Copy example config files to the config directory ## - echononl " Copy example config files to the config directory.." if [[ ${dovecot_major_version} -eq 2 ]] && [[ ${dovecot_minor_version} -lt 4 ]] ; then cp -r /usr/local/dovecot-${_version}/share/doc/dovecot/example-config/* \ /usr/local/dovecot-${_version}/etc/dovecot/ > /dev/null 2>&1 if [ "$?" = 0 ]; then echo -e "$rc_done" else echo -e "$rc_failed" error 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 if [[ $dovecot_major_version -gt 2 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then # - edit /usr/local/dovecot/etc/dovecot/dovecot.conf # - # - protocols { # - imap = yes # - lmtp = yes # - pop3 = yes # - sieve = yes # - } # - # - base_dir = /run/dovecot # - state_dir = /run/dovecot # - # - listen = $ipv4 $ipv6 # - # - mail_home = /var/vmail/%{user | domain}/%{user | username} # - mail_path = ~/Maildir # - mail_driver = Maildir # - # - shutdown_clients = no # - # - ssl_server { # - ssl = yes # - cert_file = /etc/dovecot/ssl/mailserver.crt # - key_file = /etc/dovecot/ssl/mailserver.key # - } # - _conf_file="/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf" echononl " Delete block 'namespace inbox' in file '$(basename "${_conf_file}")'.." if grep -qE '^\s*namespace\s+inbox\s*{' "${_conf_file}"; then delete_code_block "namespace inbox" "${_conf_file}" if [[ $? -gt 1 ]] ; then echo -e "$rc_failed" error "Deleting block 'namespace inbox' in file '$(basename "${_conf_file}")' failed!" else echo -e "$rc_done" fi else echo -e "$rc_skipped" fi _protocols_block="protocols {\n imap = yes\n lmtp = yes\n pop3 = yes\n sieve = yes\n}" if [[ -n "$ipv6" ]]; then _listen="$ipv4 $ipv6" else _listen="$ipv4" fi _base_dir="/run/dovecot" _state_dir="/run/dovecot" _mail_home="/var/vmail/%{user | domain}/%{user | username}" _mail_driver="Maildir" _mail_path="~/Maildir" _shutdown_clients="no" _cert_file="/etc/dovecot/ssl/mailserver.crt" _key_file="/etc/dovecot/ssl/mailserver.key" _ssl_server_block="ssl_server {\n ssl = yes\n cert_file = ${_cert_file}\n key_file = ${_key_file}\n}" echononl " Adjust file $(basename "${_conf_file}").." # # Delete all lines that begin with !include and also delete the following line # # if it is empty or contains only whitespace. # # # sed -i '/^!include/ { # N # /^\(!include.*\n[[:space:]]*\)$/d # /^!include.*/d # }' "${_conf_file}" || _failed=true # Delete all lines beginning with !include, together with all comment lines # directly preceding it (#...) - even several in a row, and also the line # following it if it is empty or only contains whitespace. # awk ' { zeile[NR] = $0 typ[NR] = "keep" if ($0 ~ /^[[:space:]]*#/) typ[NR] = "comment" if ($0 ~ /^[[:space:]]*$/) typ[NR] = "empty" if ($0 ~ /^[[:space:]]*!include/) typ[NR] = "include" } END { for (i = 1; i <= NR; i++) { if (typ[i] == "include") { # Vorherige Kommentarzeilen löschen j = i - 1 while (j > 0 && typ[j] == "comment") { typ[j] = "delete" j-- } # Include-Zeile löschen typ[i] = "delete" # Nachfolgende Leerzeile löschen (falls vorhanden) if (typ[i+1] == "empty") { typ[i+1] = "delete" } } } for (i = 1; i <= NR; i++) { if (typ[i] != "delete") print zeile[i] } } ' "${_conf_file}" > "${_conf_file}.tmp" && mv "${_conf_file}.tmp" "${_conf_file}" if grep -qE '^\s*protocols\s*{' "${_conf_file}"; then sed -i "/^\s*protocols\s*{/,/^}/c\ ${_protocols_block}" ${_conf_file} || _failed=true else cat <> "${_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 <> "${_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 <> "${_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 <> "${_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 <> "${_conf_file}" || _failed=true # SSL/TLS Configuration $(echo -e "${_ssl_server_block}") EOF fi cat <> "${_conf_file}" || _failed=true # Most of the actual configuration gets included below. The filenames are # first sorted by their ASCII value and parsed in that order. The 00-prefixes # in filenames are intended to make it easier to understand the ordering. !include_try conf.d/*.conf # A config file can also tried to be included without giving an error if # it's not found: !include_try local.conf EOF if ! $_failed ; then echo -e "$rc_done" else echo -e "$rc_failed" error "Adjusting Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf failed" echo "" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interupted by user" fi else ## - edit /usr/local/dovecot/etc/dovecot/dovecot.conf ## - ## - protocols = imap pop3 sieve ## - listen = $ipv4 $ipv6 ## - base_dir =/run/dovecot/ ## - state_dir = /run/dovecot ## - shutdown_clients = no ## - ## - dict { ## - expire = $db_driver:/usr/local/dovecot/etc/dovecot/sql-dict.conf.ext ## - } ## - echononl " Adjust file dovecot.conf.." if [[ -n "$ipv6" ]]; then perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(listen\ ?=.*)#\1\#\# \2\n\1listen = $ipv4 $ipv6#g" \ /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true else perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(listen\ ?=.*)#\1\#\# \2\n\1listen = $ipv4#g" \ /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true fi perl -i -n -p -e "s#^([ ]*)\#?\ ?(protocols\ ?=.*)#\1\#\# \2\n\1protocols = imap pop3 sieve#g" \ /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true perl -i -n -p -e "s#^([ ]*)\#?\ ?(base_dir\ ?=.*)#\1\#\# \2\n\1base_dir = /run/dovecot/\n\nstate_dir = /run/dovecot#g" \ /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true perl -i -n -p -e "s#^([ ]*)\#?\ ?(shutdown_clients\ ?=.*)#\1\#\# \2\n\1shutdown_clients = no#g" \ /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true if $plugin_expire ; then perl -i -n -p \ -e "s#^([ ]*)(dict\ +{.*)#\1\2\n\1 expire = $db_driver:/usr/local/dovecot/etc/dovecot/sql-dict.conf.ext#g" \ /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf || _failed=true fi if ! $_failed ; then echo -e "$rc_done" else echo -e "$rc_failed" fatal "Adjusting Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf failed" fi fi blank_line 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 </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 </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 : > "${log_file}" if [[ $dovecot_major_version -gt 2 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then _conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf" # edit /usr/local/dovecot/etc/dovecot/conf.d/10-master.conf # # default_process_limit = 1024 # default_client_limit = 10240 # # default_vsz_limit = 512M # # !! Bemerkung !! # # Das Hochsetzen des default_client_limit Parameters auf einen Wert größer # als 1024 geht nur dann wenn auch die Anzahl der zulässigen "open files" # (default = 1024) geändert wird. # # # Systemd System: # =============== # # In der service datei (z.Bsp. /etc/systemd/system/multi-user.target.wants/dovecot.service) # den Wert 'LimitNOFILE' hochsetzen: # # LimitNOFILE=32768 (must be greater or equal of 'default_client_limit') # # systemctl daemon-reload # systemctl restart dovecot.service # # Im Falle von LX containern muss zusätzlich auf dem hostsystem # in der datei '/etc/systemd/system.conf' der Wert für 'DefaultLimitNOFILE' # hochgesetzt werden. # # System V systems: # ================= # Das Hochsetzen des default_client_limit Parameters auf einen Wert größer # als 1024 geht nur dann wenn auch die Anzahl der zulässigen "open files" # (default = 1024) geändert wird. Z.Bsp. in der Datei /etc/init.d/dovecot # durch Einfügen der zeile: # ulimit -n 32768 # # Linux VServer: # put the following lines into /etc/security/limits.conf # # @staff hard nofile 32768 # root hard nofile 32768 # # !! Mybe you have also create file /etc/vservers/*/ulimits/nofiles.hard # with the same contents: # # @staff hard nofile 32768 # @adm hard nofile 32768 # root hard nofile 32768 # # see also http://linux-vserver.org/Ulimit_Nofiles # # # service imap-login { # inet_listener imap { # address = $imap_listener_adresses # } # # inet_listener imaps { # address = $imaps_listener_adresses # # } # # process_min_avail = 16 # } # # service pop3-login { # inet_listener pop3 { # address = $pop_listener_adresses # # } # inet_listener pop3s { # address = $pops_listener_adresses # # } # } # # service submission-login { # # inet_listener submission { # #port = 587 # } # # inet_listener submissions { # #port = 465 # } # } # # service lmtp { # # unix_listener /var/spool/postfix/private/dovecot-lmtp { # user = postfix # group = postfix # mode = 0660 # } # # # Create inet listener only if you can't use the above UNIX socket # #inet_listener lmtp { # # Avoid making LMTP visible for the entire internet # #address = # #port = # #} # } # # service imap { # # # tell imap to do post-login lookup using a socket called "imap-postlogin" # executable = imap post-login # # # Most of the memory goes to mmap()ing files. You may need to increase this # # limit if you have huge mailboxes. # #vsz_limit = $default_vsz_limit # # # Max. number of IMAP processes (connections) # #process_limit = 1024 # } # # service pop3 { # # # tell imap to do post-login lookup using a socket called "imap-postlogin" # executable = pop3 post-login # # # Max. number of POP3 processes (connections) # #process_limit = 1024 # } # # service submission { # # # Max. number of SMTP Submission processes (connections) # #process_limit = 1024 # } # # service auth { # # # Auth Listener (XMPP - Jabber) # inet_listener { # address = $xmpp_listener_addresses # port = $xmpp_listener_port # } # # unix_listener auth-userdb { # mode = 0666 # user = dovecot # group = dovecot # } # # unix_listener /var/spool/postfix/private/dovecot-auth { # mode = 0666 # user = postfix # group = postfix # } # # } # # service auth-worker { # # Auth worker process is run as root by default, so that it can access # # /etc/shadow. If this isn't necessary, the user should be changed to # # $SET:default_internal_user. # #user = root # } # # service dict { # # If dict proxy is used, mail processes should have access to its socket. # # For example: mode=0660, group=vmail and global mail_access_groups=vmail # unix_listener dict { # #mode = 0600 # #user = # #group = # } # } # echononl " Adjusting file $(basename "${_conf_file}").." :> "${_conf_file}" _param="default_process_limit" _val=1024 if grep -qE "^\s*${_param}\s*=" "${_conf_file}"; then perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \ "${_conf_file}" >> "${log_file}" 2>&1 || _failed=true else cat <> "${_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 <> "${_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 <> "${_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 <> "${log_file}" 2>&1 if [[ $? -gt 0 ]]; then _failed=true fi read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 if [[ $? -gt 0 ]]; then _failed=true fi read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 if [[ $? -gt 0 ]]; then _failed=true fi read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 if [[ $? -gt 0 ]]; then _failed=true fi read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 if [[ $? -gt 0 ]]; then _failed=true fi read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 if [[ $? -gt 0 ]]; then _failed=true fi read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 if [[ $? -gt 0 ]]; then _failed=true fi if ${xmpp_listener} ; then read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 if [[ $? -gt 0 ]]; then _failed=true fi read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 if [[ $? -gt 0 ]]; then _failed=true fi read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 if [[ $? -gt 0 ]]; then _failed=true fi # if grep -qE "^\s*service\s+auth\s*{" "${_conf_file}"; then # replace_code_block "service auth" "${NEW_BLOCK}" "${_conf_file}" # # if [[ $? -gt 0 ]]; then # _failed=true # fi # else # echo -e "\n${NEW_BLOCK}" >> "${_conf_file}" # fi if ! $_failed ; then echo -e "$rc_done" else echo -e "$rc_failed" error "Adjusting Adjusting file ${_conf_file} failed" error "$(cat "${_conf_file}")" echo "" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interupted by user" fi else ## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-master.conf ## - ## - default_process_limit = 1024 ## - default_client_limit = 10240 ## - ## - default_vsz_limit = 512M ## - ## - !! Bemerkung !! ## - ## - Das Hochsetzen des default_client_limit Parameters auf einen Wert größer ## - als 1024 geht nur dann wenn auch die Anzahl der zulässigen "open files" ## - (default = 1024) geändert wird. ## - ## - ## - Systemd System: ## - =============== ## - ## - In der service datei (z.Bsp. /etc/systemd/system/multi-user.target.wants/dovecot.service) ## - den Wert 'LimitNOFILE' hochsetzen: ## - ## - LimitNOFILE=32768 (must be greater or equal of 'default_client_limit') ## - ## - systemctl daemon-reload ## - systemctl restart dovecot.service ## - ## - Im Falle von LX containern muss zusätzlich auf dem hostsystem ## - in der datei '/etc/systemd/system.conf' der Wert für 'DefaultLimitNOFILE' ## - hochgesetzt werden. ## - ## - System V systems: ## - ================= ## - Das Hochsetzen des default_client_limit Parameters auf einen Wert größer ## - als 1024 geht nur dann wenn auch die Anzahl der zulässigen "open files" ## - (default = 1024) geändert wird. Z.Bsp. in der Datei /etc/init.d/dovecot ## - durch Einfügen der zeile: ## - ulimit -n 32768 ## - ## - Linux VServer: ## - put the following lines into /etc/security/limits.conf ## - ## - @staff hard nofile 32768 ## - root hard nofile 32768 ## - ## - !! Mybe you have also create file /etc/vservers/*/ulimits/nofiles.hard ## - with the same contents: ## - ## - @staff hard nofile 32768 ## - @adm hard nofile 32768 ## - root hard nofile 32768 ## - ## - see also http://linux-vserver.org/Ulimit_Nofiles ## - ## - ## - ## - service auth { ## - ## - # Auth Listener (XMPP - Jabber) ## - inet_listener { ## - address = $xmpp_listener_addresses ## - port = $xmpp_listener_port ## - } ## - .. ## - unix_listener auth-userdb { ## - mode = 0666 ## - user = dovecot ## - group = dovecot ## - } ## - .. ## - unix_listener /var/spool/postfix/private/dovecot-auth { ## - mode = 0666 ## - user = postfix ## - group = postfix ## - } ## - .. ## - } ## - ## - service imap-login { ## - inet_listener imap { ## - address = $imap_listener_adresses ## - .. ## - } ## - inet_listener imaps { ## - address = $imaps_listener_adresses ## - .. ## - } ## - ## - process_min_avail = 16 ## - } ## - ## - service pop3-login { ## - inet_listener pop3 { ## - address = $pop_listener_adresses ## - .. ## - } ## - inet_listener pop3s { ## - address = $pops_listener_adresses ## - .. ## - } ## - } ## - echononl " Adjusting file 10-master.conf.." perl -i.ORIG -n -p -e "s#^([ ]*)(unix_listener\ +auth-userdb.*)#\1\2\n\1 mode = 0666\n\1 user = dovecot\n\1 group = dovecot#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true perl -i -n -p -e "s#^([ ]*)(\#.*Postfix.*smtp-auth.*)#\1\2\n\1unix_listener /var/spool/postfix/private/dovecot-auth {\n\1 mode = 0666\n\1 user = postfix\n\1 group = postfix\n\1}#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true perl -i -n -p -e "s#^([ ]*)(inet_listener\ +imap\ .*)#\1\2\n\1 address = $imap_listener_adresses#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true perl -i -n -p -e "s#^([ ]*)(inet_listener\ +imaps.*)#\1\2\n\1 address = $imaps_listener_adresses#g#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true perl -i -n -p -e "s#^([ ]*)(\#?process_min_avail\ ?=.*)#\1\#\# \2\n\1process_min_avail = 16#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true perl -i -n -p -e "s#^([ ]*)(inet_listener\ +pop3\ .*)#\1\2\n\1 address = $pop_listener_adresses#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true perl -i -n -p -e "s#^([ ]*)(inet_listener\ +pop3s.*)#\1\2\n\1 address = $pops_listener_adresses#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true if $xmpp_listener ; then perl -i -n -p -e "s#^([ ]*)(service auth\s+\{.*)#\1\2\n\n \# Auth Listener (XMPP - Jabber)\n inet_listener {\n address = $xmpp_listener_addresses\n port = $xmpp_listener_port\n }\n#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true fi ## - setting default prozcess/client limit ## - perl -i -n -p -e "s#^([ ]*\#?[ ]*)(default_process_limit.*)#\1\2\ndefault_process_limit = 1024#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true perl -i -n -p -e "s#^([ ]*\#?[ ]*)(default_client_limit.*)#\1\2\ndefault_client_limit = 10240#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true perl -i -n -p -e "s#^([ ]*\#?[ ]*)(default_vsz_limit.*)#\1\2\ndefault_vsz_limit = 512M#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true if ! $_failed ; then echo -e "$rc_done" else echo -e "$rc_failed" fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf failed" fi fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-master.conf blank_line echononl " Create Cert/Key Directory '$cert_base_dir'.." if [[ ! -d "$cert_base_dir" ]] ; then mkdir -p "$cert_base_dir" > $log_file 2>&1 if [[ $? -eq 0 ]] ; then echo -e "$rc_done" echononl " Change Permissions for Cert/Key Directory '$cert_base_dir'.." chmod 755 "$cert_base_dir" > $log_file 2>&1 if [[ $? -eq 0 ]] ; then echo -e "$rc_done" else echo -e "$rc_failed" error "$(cat "$log_file")" fi else echo -e "$rc_failed" error "$(cat "$log_file")" fi else echo -e "$rc_skipped" fi ## - Since dovecot version 2.3.x SSL DH parameters will be stored ## - permanently on filesystem. So we have to create such a file ## - ## - openssl dhparam -out /etc/postfix/ssl/dh_4096.pem` ## - echononl " Create SSL DH parameters '$dh_pem_file'.." if [[ $dovecot_major_version -ge 3 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -ge 3 ]] ); then if [[ ! -f "$dh_pem_file" ]] ; then echo -en "$rc_wait" if [[ "$os_dist" = "debian" ]] && [[ $os_version -gt 11 ]] ; then openssl dhparam -out "$dh_pem_file" 4096 > /dev/null 2>&1 else openssl dhparam -dsaparam -out "$dh_pem_file" 4096 > /dev/null 2>&1 fi if [[ $? -eq 0 ]]; then echo -e "$rc_done" else echo -e "$rc_failed" error "Creating DH parameter file '$dh_pem_file' failed." fi else echo -e "$rc_skipped" fi else echo -e "$rc_skipped" fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-ssl.conf # _failed=false _conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf" if [[ $dovecot_major_version -gt 2 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then # edit /usr/local/dovecot/etc/dovecot/conf.d/10-ssl.conf # # ssl_server { # # ssl = required # # # Preferred permissions: root:root 0444 # cert_file = $server_cert # # # Preferred permissions: root:root 0400 # key_file = $server_key # # # Path to the Diffie-Hellman parameters file. This setting isn't needed if using only ECDSA certificates. # # # # You can generate a new parameters file by, for example, running # # # # openssl dhparam -out dh.pem 4096 # # # # on a machine with sufficient entropy (this may take some time). # dh_file = $dh_pem_file # # # SSL ciphers to use # ssl_cipher_list = ${ssl_cipher_list} # # # # Whether to give preference to the server's cipher list over a client's list (server) # # or vice versa (client) # # # # For TLSv1.3 server ciphers should not longer be preferred # prefer_ciphers = client # # # The minimum SSL protocol version Dovecot accepts. # # # # This setting is used for both incoming and outgoing SSL connections. # min_protocol = TLSv1.2 # } echononl " Adjusting file $(basename "${_conf_file}").." :> "${log_file}" read -r -d '' NEW_BLOCK <> "${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 <> "${_conf_file}" || _failed=true # The minimum SSL protocol version Dovecot accepts. # # This setting is used for both incoming and outgoing SSL connections. ${_param} = ${_val} EOF fi if ! $_failed ; then echo -e "$rc_done" else echo -e "$rc_failed" error "Adjusting Adjusting file ${_conf_file} failed" error "$(cat "${log_file}")" echo "" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interupted by user" fi else ## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-ssl.conf ## - ## - ssl = required ## - ## - ssl_cert = <$server_cert ## - ssl_key = <$server_key ## - ## - # - 'ssl_dh_parameters_length' is obsolete and no longer needed ## - #ssl_dh_parameters_length = 2048 ## - ## - # - 'ssl_protocols has been' replaced by ssl_min_protocol ## - #ssl_protocols = !SSLv3 ## - ssl_min_protocol = TLSv1.2 ## - ## - ssl_cipher_list = ${ssl_cipher_list} ## - ## - ssl_prefer_server_ciphers = yes ## - ## - ## - there are another possibilities to handle certs, but this did'nt work ## - as i expected.. ## - #local_name imap.warenform.de { ## - # ssl_cert = <$imap_cert ## - # ssl_key = <$imap_key ## - #} ## - #local_name pop.warenform.de { ## - # ssl_cert = <$pop_cert ## - # ssl_key = <$pop_key ## - #} ## - echononl " Backup file $(basename "${_conf_file}").." if [[ ! -f "${_conf_file}.ORIG" ]] ; then cp -a "${_conf_file}" "${_conf_file}.ORIG" > ${log_file} 2>&1 if [[ $? -gt 0 ]] ; then echo -e "$rc_failed" error "$(cat $log_file)" else echo -e "$rc_done" fi else echo -e "$rc_skipped" fi :> "${log_file}" echononl " Adjusting file $(basename "${_conf_file}").." _param="ssl" _val="required" if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \ "${_conf_file}" || _failed=true else cat <> "${_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 <> "${_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 <> "${_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 <> "${_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 <> "${_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 <> "${_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 <> "${_conf_file}" || _failed=true # Prefer the server's order of ciphers over client's. ${_param} = ${_val} EOF fi if ! $_failed ; then echo -e "$rc_done" else echo -e "$rc_failed" error "Adjusting '$(basename "${_conf_file}") failed" echo "" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interupted by user" fi fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-ssl.conf # edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf # _failed=false _conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf" if [[ $dovecot_major_version -gt 2 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then # edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf # # mail_home = /var/vmail/%{user | domain}/%{user | username} # mail_driver = Maildir # mail_path = ~/Maildir # # mail_uid = vmail # mail_gid = vmail # # first_valid_uid = ${vmail_uid} # last_valid_uid = ${vmail_uid} # # first_valid_gid = ${vmail_gid} # last_valid_gid = ${vmail_gid} # # mail_temp_dir = /var/vmail/tmp # # auth_socket_path = /run/dovecot/auth-userdb # # mail_plugins = quota acl # # mailbox_list_index # echononl " Adjusting file '$(basename "${_conf_file}")'.." :> "${log_file}" if grep -qE '^\s*mail_home\s*=' "${_conf_file}" \ || grep -qE '^\s*mail_driver\s*=' "${_conf_file}" \ || grep -qE '^\s*mail_path\s*=' "${_conf_file}" ; then replace_variable \ "mail_home" \ '/var/vmail/%{user | domain}/%{user | username}' \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then _failed=true fi replace_variable \ "mail_driver" \ 'Maildir' \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then _failed=true fi replace_variable \ "mail_path" \ '~/Maildir' \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then _failed=true fi else cat <<'EOF' >> "${_conf_file}" || _failed=true mail_home= /var/vmail/%{user | domain}/%{user | username}' mail_driver = Maildir mail_path = ~/Maildir EOF if [[ $? -gt 0 ]] ; then _failed=true fi fi if grep -qE '^\s*mail_uid\s*=' "${_conf_file}" \ || grep -qE '^\s*mail_uid\s*=' "${_conf_file}" ; then replace_variable \ "mail_uid" \ 'vmail' \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then _failed=true fi replace_variable \ "mail_gid" \ 'vmail' \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then _failed=true fi else cat <<'EOF' >> "${_conf_file}" || _failed=true # System user and group used to access mails. mail_uid = vmail mail_gid = vmail EOF if [[ $? -gt 0 ]] ; then _failed=true fi fi if grep -qE '^\s*first_valid_uid\s*=' "${_conf_file}" \ || grep -qE '^\s*last_valid_uid\s*=' "${_conf_file}" ; then replace_variable \ "first_valid_uid" \ "${vmail_uid}" \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then _failed=true fi replace_variable \ "last_valid_uid" \ "${vmail_uid}" \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then _failed=true fi else cat <> "${_conf_file}" || _failed=true # Valid UID range for users allowed to login first_valid_uid = ${vmail_uid} last_valid_uid = ${vmail_uid} EOF if [[ $? -gt 0 ]] ; then _failed=true fi fi if grep -qE '^\s*first_valid_gid\s*=' "${_conf_file}" \ || grep -qE '^\s*last_valid_gid\s*=' "${_conf_file}" ; then replace_variable \ "first_valid_gid" \ "${vmail_gid}" \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then _failed=true fi replace_variable \ "last_valid_gid" \ "${vmail_gid}" \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then _failed=true fi else cat <> "${_conf_file}" || _failed=true # Valid GID range for users allowed to login first_valid_gid = ${vmail_gid} last_valid_gid = ${vmail_gid} EOF if [[ $? -gt 0 ]] ; then _failed=true fi fi if grep -qE '^\s*mail_temp_dir\s*=' "${_conf_file}" ; then replace_variable \ "mail_temp_dir" \ "/var/vmail/tmp" \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then _failed=true fi else cat <> "${_conf_file}" || _failed=true # The directory in which LDA/LMTP will temporarily store incoming message data # that is above 128kB in size. mail_temp_dir = /var/vmail/tmp EOF if [[ $? -gt 0 ]] ; then _failed=true fi fi if grep -qE '^\s*auth_socket_path\s*=' "${_conf_file}" ; then replace_variable \ "auth_socket_path" \ "/run/dovecot/auth-userdb" \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then _failed=true fi else cat <> "${_conf_file}" || _failed=true # The UNIX socket path to the master authentication server for finding users. auth_socket_path = /run/dovecot/auth-userdb EOF if [[ $? -gt 0 ]] ; then _failed=true fi fi if grep -qE '^\s*mail_plugins\s*=' "${_conf_file}" ; then replace_variable \ "mail_plugins" \ "quota acl" \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then _failed=true fi else cat <> "${_conf_file}" || _failed=true # A list of mail plugins to load. mail_plugins = quota acl EOF if [[ $? -gt 0 ]] ; then _failed=true fi fi if grep -qE '^\s*mailbox_list_index\s*=' "${_conf_file}" ; then replace_variable \ "mailbox_list_index" \ "yes" \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then _failed=true fi else cat <> "${_conf_file}" || _failed=true # Dovecot indexes live at the root of user's mailbox storage, and allows quick lookup # of mailbox status instead of needing to open all mailbox indexes separately. # # Enabling this optimizes the server reply to IMAP STATUS commands, which are commonly # issued by clients. This also needs to be enabled if you wish to enable the # IMAP NOTIFY extension. mailbox_list_index = yes EOF if [[ $? -gt 0 ]] ; then _failed=true fi fi if ! $_failed ; then echo -e "$rc_done" else echo -e "$rc_failed" error "Adjusting '$(basename "${_conf_file}") failed" echo "" echononl "continue anyway [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/no]: " read OK done [[ $OK = "yes" ]] || fatal "Interupted by user" fi else ## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf ## - ## - mail_location = maildir:/var/vmail/%d/%n/Maildir ## - ## - mail_uid = vmail ## - mail_gid = vmail ## - ## - first_valid_uid = 5000 ## - last_valid_uid = 5000 ## - ## - mail_temp_dir = /var/vmail/tmp ## - ## - first_valid_gid = 5000 ## - last_valid_gid = 5000 ## - ## - auth_socket_path = /run/dovecot/auth-userdb ## - mail_plugins = quota acl | mail_plugins = quota acl expire ## - ## - mailbox_list_index = yes ## - echononl " Adjusting file '$(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 <