diff --git a/install_update_dovecot-2.4.sh b/install_update_dovecot-2.4.sh index 82318c6..9411a58 100755 --- a/install_update_dovecot-2.4.sh +++ b/install_update_dovecot-2.4.sh @@ -36,6 +36,8 @@ rc_skipped="\033[71G[ \033[1;37mskipped\033[m ]" rc_wait="\033[71G[ \033[5m\033[1m..\033[m ]" rc_not_yet_implemented="\033[71G[ \033[1;33mNot Yet Implemented\033[m ]" +rc_already_done="\033[71G[ \033[32mAlready Done\033[m ]" +rc_not_needed_anymore="\033[71G[ \033[1;37mNot Needed Anymore\033[m ]" # ------------- @@ -270,7 +272,7 @@ replace_or_append_code_block() { mv "$tmp_file" "$file" rm -f _new_block_to_append.tmp - echo "Block '$block_name' wurde ersetzt." + #echo "Block '$block_name' wurde ersetzt." return 0 } @@ -390,13 +392,13 @@ replace_or_append_code_block_if_keyval() { 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." + #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)." + #echo "Block '$block_name' wurde ersetzt (Bedingung erfüllt)." return 0 } @@ -1295,7 +1297,7 @@ echo "" echo -e "\tInstall Plugin 'expire'.......: $plugin_expire" echo "" -INSTALL_UPDATE_ENVIRONMENT_FILE="${_src_base_dir}/conf/install_update_dovecot-2.4..env" +INSTALL_UPDATE_ENVIRONMENT_FILE="${_src_base_dir}/conf/install_update_dovecot-2.4.env" cat < ${INSTALL_UPDATE_ENVIRONMENT_FILE} #!/usr/bin/env bash @@ -1543,13 +1545,13 @@ replace_or_append_code_block() { 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." + #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." + #echo "Block '$block_name' wurde ersetzt." return 0 } @@ -1669,13 +1671,13 @@ replace_or_append_code_block_if_keyval() { 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." + #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)." + #echo "Block '$block_name' wurde ersetzt (Bedingung erfüllt)." return 0 } @@ -1905,12 +1907,12 @@ replace_or_append_code_block_if_keyval_strict() { 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." + #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." + #echo "Block '$block_name' vorhanden, aber Bedingung '$required_key = $required_value' nicht erfüllt. Keine Änderung vorgenommen." return 0 fi @@ -1966,7 +1968,7 @@ delete_code_block() { ' "$file" > "$tmp_file" mv "$tmp_file" "$file" - echo "Block '$block_name' wurde gelöscht." + #echo "Block '$block_name' wurde gelöscht." return 0 } @@ -2037,7 +2039,7 @@ delete_code_block_with_comments() { ' "$file" > "$tmp_file" mv "$tmp_file" "$file" - echo "Block '$block_name' inkl. vorangehender Kommentare wurde gelöscht." + #echo "Block '$block_name' inkl. vorangehender Kommentare wurde gelöscht." return 0 } @@ -2095,7 +2097,7 @@ replace_variable() { mv "$tmp_file" "$file" rm -f _missing_var.tmp - echo "Variable '$var_name' wurde ersetzt." + #echo "Variable '$var_name' wurde ersetzt." return 0 } @@ -2105,7 +2107,7 @@ replace_or_append_variable() { local file="$3" if [[ -z "$var_name" || -z "$new_value" || -z "$file" ]]; then - echo "Verwendung: replace_variable \"variablenname\" \"neuer_wert\" \"/pfad/zur/datei\"" + #echo "Verwendung: replace_variable \"variablenname\" \"neuer_wert\" \"/pfad/zur/datei\"" return 1 fi @@ -2232,7 +2234,7 @@ delete_variable_with_comments() { ' "$file" > "$tmp_file" mv "$tmp_file" "$file" - echo "Variable '$var_name' inkl. zugehöriger Kommentare wurde gelöscht." + #echo "Variable '$var_name' inkl. zugehöriger Kommentare wurde gelöscht." return 0 } @@ -2810,6 +2812,23 @@ else echo -e "$rc_skipped" fi +echononl " Disable dovecot service.." +if systemctl list-units --full -all | grep -Fq "dovecot.service" 2> /dev/null ; then + if $systemd_support ; then + systemctl disable dovecot > /dev/null 2>&1 + if [ "$?" = 0 ]; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + error "Stopping dovecot service failed" + fi + else + echo -e "$rc_skipped" + fi +else + echo -e "$rc_skipped" +fi + blank_line echononl " Remove dovecot service file if exists.." @@ -2821,6 +2840,14 @@ if [[ -f "/etc/systemd/system/dovecot.service" ]] ; then else echo -e "$rc_done" fi +elif [[ -f "/usr/lib/systemd/system/dovecot.service" ]] ; then + rm -f "/usr/lib/systemd/system/dovecot.service" > /dev/null 2>&1 + if [[ "$?" -gt 0 ]]; then + echo -e "$rc_failed" + error "Removing file '/usr/lib/systemd/system/dovecot.service' failed." + else + echo -e "$rc_done" + fi else echo -e "$rc_skipped" fi @@ -2834,6 +2861,14 @@ if [[ -f "/etc/systemd/system/dovecot.socket" ]] ; then else echo -e "$rc_done" fi +elif [[ -f "/usr/lib/systemd/system/dovecot.socket" ]] ; then + rm -f "/usr/lib/systemd/system/dovecot.socket" > /dev/null 2>&1 + if [[ "$?" -gt 0 ]]; then + echo -e "$rc_failed" + error "Removing systemd's socket file '/usr/lib/systemd/system/dovecot.socket' failed." + else + echo -e "$rc_done" + fi else echo -e "$rc_skipped" fi @@ -3209,6 +3244,44 @@ EOF echo -e "$rc_skipped" fi + _conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-quota.conf" + echononl " Create empty file '$(basename "${_conf_file}")'.." + if [[ ! -f "${_conf_file}" ]] ; then + _failed=false + cat <<'EOF' > "${_conf_file}" 2> "${log_file}" +## +## Quota configuration. +## +EOF + if [ "$?" = 0 ]; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + error "Creating file '${_conf_file}' failed!" + fi + else + echo -e "$rc_skipped" + fi + + _conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-acl.conf" + echononl " Create empty file '$(basename "${_conf_file}")'.." + if [[ ! -f "${_conf_file}" ]] ; then + _failed=false + cat <<'EOF' > "${_conf_file}" 2> "${log_file}" +## +## Mailbox access control lists (ACL) +## +EOF + if [ "$?" = 0 ]; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + error "Creating file '${_conf_file}' failed!" + fi + else + echo -e "$rc_skipped" + fi + blank_line @@ -3373,7 +3446,7 @@ if [[ $dovecot_major_version -gt 2 ]] \ # - # - mail_home = /var/vmail/%{user | domain}/%{user | username} # - mail_path = ~/Maildir - # - mail_driver = Maildir + # - mail_driver = maildir # - # - shutdown_clients = no # - @@ -3408,7 +3481,7 @@ if [[ $dovecot_major_version -gt 2 ]] \ _state_dir="/run/dovecot" _mail_home="/var/vmail/%{user | domain}/%{user | username}" - _mail_driver="Maildir" + _mail_driver="maildir" _mail_path="~/Maildir" _shutdown_clients="no" @@ -4249,7 +4322,7 @@ EOF service imap { # tell imap to do post-login lookup using a socket called "imap-postlogin" - executable = imap post-login + #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. @@ -4268,7 +4341,7 @@ EOF service pop3 { # tell imap to do post-login lookup using a socket called "imap-postlogin" - executable = pop3 post-login + #executable = pop3 post-login # Max. number of POP3 processes (connections) #process_limit = 1024 @@ -4384,8 +4457,8 @@ 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 = + mode = 0600 + user = vmail #group = } } @@ -4950,7 +5023,7 @@ if [[ $dovecot_major_version -gt 2 ]] \ # edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf # # mail_home = /var/vmail/%{user | domain}/%{user | username} - # mail_driver = Maildir + # mail_driver = maildir # mail_path = ~/Maildir # # mail_uid = vmail @@ -4989,7 +5062,7 @@ if [[ $dovecot_major_version -gt 2 ]] \ replace_variable \ "mail_driver" \ - 'Maildir' \ + 'maildir' \ "${_conf_file}" >> "${log_file}" 2>&1 if [[ $? -gt 0 ]] ; then @@ -5009,7 +5082,7 @@ if [[ $dovecot_major_version -gt 2 ]] \ cat <<'EOF' >> "${_conf_file}" || _failed=true mail_home= /var/vmail/%{user | domain}/%{user | username}' -mail_driver = Maildir +mail_driver = maildir mail_path = ~/Maildir EOF @@ -5525,51 +5598,6 @@ EOF fi # if grep -qE "^\s*namespace\s+inbox\s*{" "${_conf_file}"; then - read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 - if [[ $? -gt 0 ]]; then - _failed=true - fi - if ! $_failed ; then echo -e "$rc_done" else @@ -5859,7 +5887,7 @@ if [[ $dovecot_major_version -gt 2 ]] \ echononl " Adjusting file '$(basename "${_conf_file}")'.." - read -r -d '' NEW_BLOCK <> /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf + echononl " Add 'service stats' to file '$(basename "${_conf_file}")'.." + + read -r -d '' NEW_BLOCK <<'EOF' +service stats { + + fifo_listener stats-mail { + user = vmail + group = dovecot + mode = 0660 + } + + unix_listener stats-reader { + user = vmail + group = dovecot + mode = 0660 + } + + unix_listener stats-writer { + user = vmail + group = dovecot + mode = 0660 + } +} +EOF + + replace_or_append_code_block "service stats" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true + fi + + if ! $_failed ; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + error "Adjusting Adjusting file ${_conf_file} failed" + error "$(cat "${log_file}")" + + echo "" + echononl "continue anyway [yes/no]: " + read OK + OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" + while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do + echononl "Wrong entry! - repeat [yes/no]: " + read OK + done + [[ $OK = "yes" ]] || fatal "Interupted by user" + fi + +else + + ## - configure stats service (10-master.conf) + ## - + echononl " Add 'service stats' to file '$(basename "${_conf_file}")'.." + cat <> "${_conf_file}" service stats { - fifo_listener stats-mail { - user = vmail - group = dovecot - mode = 0660 - } + fifo_listener stats-mail { + user = vmail + group = dovecot + mode = 0660 + } - unix_listener stats-reader { - user = vmail - group = dovecot - mode = 0660 - } + unix_listener stats-reader { + user = vmail + group = dovecot + mode = 0660 + } - unix_listener stats-writer { - user = vmail - group = dovecot - mode = 0660 - } + unix_listener stats-writer { + user = vmail + group = dovecot + mode = 0660 + } } EOF -if [[ $? -gt 0 ]] ; then - echo -e "$rc_failed" - error "Configure stats service (10-master.conf) failed!" -else - echo -e "$rc_done" -fi + if [[ $? -gt 0 ]] ; then + echo -e "$rc_failed" + error "Configure stats service ($(basename "${_conf_file}")) failed!" + else + echo -e "$rc_done" + fi + +fi # Renew file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf -## - configure post-login service (10-master.conf) +## - Add script 'post-login.sh' ## - ## - see also: https://wiki.dovecot.org/PostLoginScripting ## - @@ -9216,35 +9315,63 @@ fi # Configure post-login service (10-master.conf) # _failed=false +_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf" if [[ $dovecot_major_version -gt 2 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then - echononl " Configure post-login service (10-master.conf).." + echononl " Configure post-login service ($(basename "${_conf_file}")).." - _master_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf" + read -r -d '' NEW_BLOCK <> "${_master_conf_file}" || _failed=true + # 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 -$(echo -e "${_service_imap_block}") + # Max. number of IMAP processes (connections) + #process_limit = 1024 +} EOF + replace_or_append_code_block "service imap" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true fi + read -r -d '' NEW_BLOCK <> "${_master_conf_file}" || _failed=true + # tell imap to do post-login lookup using a socket called "imap-postlogin" + executable = pop3 post-login -$(echo -e "${_service_pop3_block}") + # Max. number of POP3 processes (connections) + #process_limit = 1024 +} EOF + replace_or_append_code_block "service pop3" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true + fi + + read -r -d '' NEW_BLOCK <<'EOF' +service post-login { + # all post-login scripts are executed via script-login binary + executable = script-login /usr/local/dovecot/bin/post-login.sh + + # the script process runs as the user specified here: + user = vmail + + # this UNIX socket listener must use the same name as given to imap executable + unix_listener post-login { + } +} +EOF + + replace_or_append_code_block "service post-login" "${NEW_BLOCK}" "${_conf_file}" >> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true fi if ! $_failed ; then @@ -9264,7 +9391,6 @@ EOF [[ $OK = "yes" ]] || fatal "Interupted by user" fi - else echononl " Configure post-login service (10-master.conf)" @@ -9275,15 +9401,15 @@ else cat <> /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf service post-login { -# all post-login scripts are executed via script-login binary -executable = script-login /usr/local/dovecot/bin/post-login.sh + # all post-login scripts are executed via script-login binary + executable = script-login /usr/local/dovecot/bin/post-login.sh -# the script process runs as the user specified here: -user = vmail + # the script process runs as the user specified here: + user = vmail -# this UNIX socket listener must use the same name as given to imap executable -unix_listener post-login { -} + # this UNIX socket listener must use the same name as given to imap executable + unix_listener post-login { + } } EOF if [[ $? -gt 0 ]] ; then @@ -9302,11 +9428,246 @@ fi # Configure post-login service (10-master.conf) # edit /usr/local/dovecot/etc/dovecot/conf.d/90-quota.conf # +_failed=false +_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-quota.conf" if [[ $dovecot_major_version -gt 2 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then - echononl " Adjust file '90-quota.conf'.." - echo -e "$rc_skipped" + echononl " Adjust file '$(basename "${_conf_file}")'.." + + _key="mailbox_list_index" + _val="yes" + if grep -qE "^\s*${_key}\s*=" "${_conf_file}"; then + + replace_variable "${_key}" "${_val}" "${_conf_file}" || _failed=true + + else + cat <> "${_conf_file}" || _failed=true + +# Dovecot indexes live at the root of user's mailbox storage, and allows +# quick lookup of mailbox status instead of needing to open all mailbox +# indexes separately. +# +# Enabling this optimizes the server reply to IMAP STATUS commands, which +# are commonly issued by clients. This also needs to be enabled if you wish +# to enable the IMAP NOTIFY extension. +${_key} = ${_val} +EOF + fi + + if [[ $? -gt 0 ]] ; then + _failed=true + fi + + + read -r -d '' NEW_BLOCK <<'EOF' +mail_plugins { + quota = yes +} +EOF + if grep -qE "^\s*mail_plugins\s+{" "${_conf_file}"; then + + replace_code_block "mail_plugins" "${NEW_BLOCK}" "${_conf_file}" || _failed=true + + else + cat <> "${_conf_file}" || _failed=true + +# Enable quota plugin for tracking and enforcing the quota. +$(echo -e "${NEW_BLOCK}") +EOF + fi + + if [[ $? -gt 0 ]] ; then + _failed=true + fi + + + read -r -d '' NEW_BLOCK <<'EOF' +protocol imap { + + # Enable the IMAP QUOTA extension, allowing IMAP clients to ask for the + # current quota usage. + mail_plugins { + imap_quota = yes + } +} +EOF + + replace_or_append_code_block "protocol imap" "${NEW_BLOCK}" "${_conf_file}" || _failed=true + + if [[ $? -gt 0 ]] ; then + _failed=true + fi + + + read -r -d '' NEW_BLOCK <<'EOF' +quota "User quota" { + + # quota_storage_size + # + # Default unlimited + # Value unsigned integer + # + # See Also: + # quota_storage_extra + # quota_storage_percentage + # quota_message_count + # Quota Root + # + # Quota storage size limit for the Quota Root. This value is still + # multiplied by quota_storage_percentage and then increased by + # 'quota_storage_extra' to get the final value (in this mailbox or + # namespace). This is reported as the STORAGE limit in IMAP GETQUOTA + # commands. Using 0 as the value means the same as unlimited. + quota_storage_size = 1G +} +EOF + if grep -qE "^\s*quota \"User quota\"\s+{" "${_conf_file}"; then + + replace_code_block 'quota "User quota"' "${NEW_BLOCK}" "${_conf_file}" || _failed=true + + else + cat <> "${_conf_file}" || _failed=true + +# Per-User Quota +# -------------- +# +# You can override the quota settings in your userdb: Extra Fields. Keep global settings +# from below in configuration plugin section and override only those settings you need +# to in your userdb. +# +# Use doveadm user command to verify that the userdb returns the expected quota settings. +$(echo -e "${NEW_BLOCK}") +EOF + fi + + if [[ $? -gt 0 ]] ; then + _failed=true + fi + + + read -r -d '' NEW_BLOCK <<'EOF' +protocol !indexer-worker { + mail_vsize_bg_after_count = 100 +} +EOF + if grep -qE "^\s*protocol \!indexer-worker\s+{" "${_conf_file}"; then + + replace_code_block 'protocol !indexer-worker' "${NEW_BLOCK}" "${_conf_file}" || _failed=true + + else + cat <> "${_conf_file}" || _failed=true + +# Avoid spending excessive time waiting for the quota calculation to finish +# when mails' vsizes aren't already cached. If this many mails are opened, +# finish the quota calculation on background in indexer-worker process. Mail +# deliveries will be assumed to succeed, and explicit quota lookups will +# return internal error. +$(echo -e "${NEW_BLOCK}") +EOF + fi + + if [[ $? -gt 0 ]] ; then + _failed=true + fi + + + read -r -d '' NEW_BLOCK <<'EOF' +quota user { + warning warn-95 { + quota_storage_percentage = 95 + execute quota-warning { + args = 95 %{user} + } + } + warning warn-80 { + quota_storage_percentage = 80 + execute quota-warning { + args = 80 %{user} + } + } + warning warn-under { + quota_storage_percentage = 100 + # user is no longer over quota + threshold = under + execute quota-warning { + args = below %{user} + } + } +} +EOF + if grep -qE "^\s*quota\s+user\s+{" "${_conf_file}"; then + + replace_code_block "quota user" "${NEW_BLOCK}" "${_conf_file}" || _failed=true + + else + cat <> "${_conf_file}" || _failed=true + +# Then user's quota exceeds 80% quota-warning.sh is executed with parameter 80. +# The same goes for when quota exceeds 95%. If user suddenly receives a huge +# mail and the quota jumps from 70% to 99%, only the 95 script is executed. +$(echo -e "${NEW_BLOCK}") +EOF + fi + + if [[ $? -gt 0 ]] ; then + _failed=true + fi + + + read -r -d '' NEW_BLOCK <<'EOF' +namespace inbox { + mailbox Trash { + quota_storage_extra = 100M + } + mailbox Spam { + quota_ignore = yes + } +} + +EOF + + replace_or_append_code_block "namespace inbox" "${NEW_BLOCK}" "${_conf_file}" || _failed=true + + + if [[ $? -gt 0 ]] ; then + _failed=true + fi + + + read -r -d '' NEW_BLOCK <<'EOF' +service quota-warning { + executable = script /usr/local/bin/quota-warning.sh + # use some unprivileged user for executing the quota warnings + user = vmail + unix_listener quota-warning { + user = vmail + mode = 0666 + } +} + +EOF + + replace_or_append_code_block "service quota-warning" "${NEW_BLOCK}" "${_conf_file}" || _failed=true + + 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 @@ -9427,6 +9788,9 @@ fi ## ----------------- ## --- Configure ACL support for dovecot +echo +echo -e "\033[1mConfigure ACL support for dovecot\033[m" + ## - What to do: ## - ## - 1.) Add shared namespace @@ -9455,7 +9819,51 @@ if [[ $dovecot_major_version -gt 2 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then echononl " Add mail_plugin imap_acl to '20-imap.conf'.." - echo -e "$rc_not_yet_implemented" + + +read -r -d '' NEW_BLOCK <> "${log_file}" || _failed=true + + if ! $_failed ; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + error "Adjusting Adjusting file ${_conf_file} failed" + error "$(cat "${log_file}")" + + echo "" + echononl "continue anyway [yes/no]: " + read OK + OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" + while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do + echononl "Wrong entry! - repeat [yes/no]: " + read OK + done + [[ $OK = "yes" ]] || fatal "Interupted by user" + fi else @@ -9520,11 +9928,144 @@ fi # edit /usr/local/dovecot/etc/dovecot/conf.d/20-imap.conf # edit /usr/local/dovecot/etc/dovecot/conf.d/90-acl.conf # _failed=false +_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/90-acl.conf" if [[ $dovecot_major_version -gt 2 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then echononl " Configure acl - file '90-acl.conf'.." - echo -e "$rc_not_yet_implemented" + + read -r -d '' NEW_BLOCK <<'EOF' +mail_plugins { + acl = yes +} +EOF + + if grep -qE "^\s*mail_plugins\s+{" "${_conf_file}"; then + + replace_code_block "mail_plugins" "${NEW_BLOCK}" "${_conf_file}" || _failed=true + + else + cat <> "${_conf_file}" || _failed=true + +# Enable internal ACL support +${NEW_BLOCK} +EOF + fi + + + read -r -d '' NEW_BLOCK <<'EOF' +protocol imap { + mail_plugins { + imap_acl = yes + } +} +EOF + + if grep -qE "^\s*protocol imap\s+{" "${_conf_file}"; then + + replace_code_block "protocol imap" "${NEW_BLOCK}" "${_conf_file}" || _failed=true + + else + cat <> "${_conf_file}" || _failed=true + +# Enable the IMAP ACL commands +${NEW_BLOCK} +EOF + fi + + if grep -qE "^\s*acl_driver\s+=" "${_conf_file}"; then + + replace_variable "acl_driver" "vfile" "${_conf_file}" 2>> "${log_file}" || _failed=true + + else + cat <> "${_conf_file}" || _failed=true + +# The ACL driver to use. This setting is REQUIRED - if empty, the +# acl plugin is disabled. +# +# Currently, there is a single driver available: vfile. This driver supports +# two ways of defining the ACL configuration: +# +# - global: ACL rules are applied to all users. +# +# - per-mailbox: Each mailbox has separate ACL rules. They are stored in a +# dovecot-acl file in each mailbox (or mail_control_path) directory. This +# is the default. +EOF + fi + + + read -r -d '' NEW_BLOCK <<'EOF' + +namespace shared { + type = shared + separator = / + + # Mailboxes are visible under "shared/user@domain/" + # + # Changed: 2.4.0 The shared namespaces now use $user, + # $username and $domain template variables, rather than + # the old %%u, %%n and %%d. + prefix = shared/${user}/ + + # Mail location setting + mail_home = /var/vmail/%{user | domain}/%{user | username} + mail_driver = maildir + mail_path = ~/Maildir + mail_index_private_path = ~/Maildir/shared/%{owner_user} + + # Use the default namespace for saving subscriptions. + subscriptions = no + + # Include this namespace in LIST output when listing its parent's folders. + # + # One of: + # children Namespace prefix list listed only if it has child mailboxes. + # + # no Namespace and mailboxes not listed unless listing requests explicitly + # mailboxes under the namespace prefix. + # + # yes Namespace and mailboxes are always listed. + # + # It is still possible to list the namespace's folders by explicitly asking for them. + # For example, if this setting is no, using LIST "" * with namespace prefix "lazy-expunge/" + # won't list it, but using LIST "" lazy-expunge/* lists all folders under it. + # + # Default: yes + list = children +} +EOF + if grep -qE "^\s*namespace\s+shared\s+{" "${_conf_file}"; then + + replace_code_block "namespace shared" "${NEW_BLOCK}" "${_conf_file}" || _failed=true + + else + + cat <> "${_conf_file}" || _failed=true + +# This creates a shared/ namespace under which each user's mailboxes are. +${NEW_BLOCK} +EOF + fi + + + if ! $_failed ; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + error "Adjusting Adjusting file ${_conf_file} failed" + error "$(cat "${log_file}")" + + echo "" + echononl "continue anyway [yes/no]: " + read OK + OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" + while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do + echononl "Wrong entry! - repeat [yes/no]: " + read OK + done + [[ $OK = "yes" ]] || fatal "Interupted by user" + fi else @@ -9651,13 +10192,25 @@ EOF fi +# Renew file /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext +# _failed=false -echononl " Renew file sql-dict.conf.ext" -if [ "$db_driver" = "pgsql" ]; then +_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext" +if [[ $dovecot_major_version -gt 2 ]] \ + || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then - ## - adjust/renew file /usr/local/dovecot/etc/dovecot/sql-dict.conf.ext - ## - - cat </usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext + echononl " Renew file '$(basename "${_conf_file}")'.." + echo -e "$rc_not_yet_implemented" + +else + + echononl " Renew file '$(basename "${_conf_file}")'.." + + if [ "$db_driver" = "pgsql" ]; then + + ## - adjust/renew file /usr/local/dovecot/etc/dovecot/sql-dict.conf.ext + ## - + cat </usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext ## - if using unix-socket (host=/run/postgresql) ensure that ## - coresponding entries in pg_hba.cof fits ## - for example @@ -9731,24 +10284,24 @@ connect = host=$dbhost user=$dbuser password=$dbpassword dbname=$dbname # EXECUTE PROCEDURE merge_quota2(); map { - pattern = priv/quota/storage - table = quota2 - username_field = username - value_field = bytes + pattern = priv/quota/storage + table = quota2 + username_field = username + value_field = bytes } map { - pattern = priv/quota/messages - table = quota2 - username_field = username - value_field = messages + pattern = priv/quota/messages + table = quota2 + username_field = username + value_field = messages } EOF - if [[ "$?" -gt 0 ]]; then - _failed=true - fi + if [[ "$?" -gt 0 ]]; then + _failed=true + fi - if $plugin_expire ; then - cat <> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext + if $plugin_expire ; then + cat <> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext # CREATE TABLE expires ( # username varchar(100) not null, @@ -9780,21 +10333,22 @@ EOF map { - pattern = shared/expire/\$user/\$mailbox - table = expires - value_field = expire_stamp + pattern = shared/expire/\$user/\$mailbox + table = expires + value_field = expire_stamp - fields { - username = \$user - mailbox = \$mailbox - } + fields { + username = \$user + mailbox = \$mailbox + } } EOF - if [[ "$?" -gt 0 ]]; then - _failed=true + if [[ "$?" -gt 0 ]]; then + _failed=true + fi fi - fi - cat <> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext + + cat <> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext # CREATE TABLE user_shares ( @@ -9813,42 +10367,42 @@ EOF # COMMENT ON TABLE anyone_shares IS 'User from_user shares folders to anyone.'; map { - pattern = shared/shared-boxes/user/\$to/\$from - table = user_shares - value_field = dummy + pattern = shared/shared-boxes/user/\$to/\$from + table = user_shares + value_field = dummy - fields { - from_user = \$from - to_user = \$to - } + fields { + from_user = \$from + to_user = \$to + } } map { - pattern = shared/shared-boxes/anyone/\$from - table = anyone_shares - value_field = dummy + pattern = shared/shared-boxes/anyone/\$from + table = anyone_shares + value_field = dummy - fields { - from_user = \$from - } + fields { + from_user = \$from + } } EOF - if [[ "$?" -gt 0 ]]; then - _failed=true - fi + if [[ "$?" -gt 0 ]]; then + _failed=true + fi - if ! $_failed ; then - echo -e "$rc_done" - else - echo -e "$rc_failed" - fatal "Recreating file /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext failed" - fi + if ! $_failed ; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + fatal "Recreating file /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext failed" + fi -elif [ "$db_driver" = "mysql" ]; then + elif [ "$db_driver" = "mysql" ]; then - ## - adjust/renew file /usr/local/dovecot/etc/dovecot/sql-dict.conf.ext - ## - - cat </usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext + ## - adjust/renew file /usr/local/dovecot/etc/dovecot/sql-dict.conf.ext + ## - + cat </usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext connect = host=$dbhost user=$dbuser password=$dbpassword dbname=$dbname # CREATE TABLE quota2 ( @@ -9859,24 +10413,24 @@ connect = host=$dbhost user=$dbuser password=$dbpassword dbname=$dbname # ); map { - pattern = priv/quota/storage - table = quota2 - username_field = username - value_field = bytes +pattern = priv/quota/storage +table = quota2 +username_field = username +value_field = bytes } map { - pattern = priv/quota/messages - table = quota2 - username_field = username - value_field = messages + pattern = priv/quota/messages + table = quota2 + username_field = username + value_field = messages } EOF - if [[ "$?" -gt 0 ]]; then - _failed=true - fi + if [[ "$?" -gt 0 ]]; then + _failed=true + fi - if $plugin_expire ; then - cat <> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext + if $plugin_expire ; then + cat <> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext # CREATE TABLE expires ( # username varchar(100) not null, @@ -9887,21 +10441,21 @@ EOF map { - pattern = shared/expire/\$user/\$mailbox - table = expires - value_field = expire_stamp + pattern = shared/expire/\$user/\$mailbox + table = expires + value_field = expire_stamp - fields { - username = \$user - mailbox = \$mailbox - } + fields { + username = \$user + mailbox = \$mailbox + } } EOF - if [[ "$?" -gt 0 ]]; then - _failed=true + if [[ "$?" -gt 0 ]]; then + _failed=true + fi fi - fi - cat <> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext + cat <> /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext # CREATE TABLE user_shares ( @@ -9918,34 +10472,35 @@ EOF # ) COMMENT = 'User from_user shares folders to anyone.'; map { - pattern = shared/shared-boxes/user/\$to/\$from - table = user_shares - value_field = dummy +pattern = shared/shared-boxes/user/\$to/\$from +table = user_shares +value_field = dummy - fields { - from_user = \$from - to_user = \$to - } +fields { + from_user = \$from + to_user = \$to +} } map { - pattern = shared/shared-boxes/anyone/\$from - table = anyone_shares - value_field = dummy + pattern = shared/shared-boxes/anyone/\$from + table = anyone_shares + value_field = dummy - fields { - from_user = \$from - } + fields { + from_user = \$from + } } EOF - if [[ "$?" -gt 0 ]]; then - _failed=true - fi - if ! $_failed ; then - echo -e "$rc_done" - else - echo -e "$rc_failed" - fatal "Recreating file /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext failed" + if [[ "$?" -gt 0 ]]; then + _failed=true + fi + if ! $_failed ; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + fatal "Recreating file /usr/local/dovecot-${_version}/etc/dovecot/sql-dict.conf.ext failed" + fi fi fi @@ -10012,22 +10567,30 @@ else fi # edit /usr/local/dovecot/etc/dovecot/conf.d/20-managesieve.conf -#_set_link="" -#echo -#echo "Set symlink " -#echo -e -n " /usr/local/dovecot --> dovecot-${_version} /usr/local/dovecot? [y/n]: " -#read _set_link -#if [ "y" = "$_set_link" -o "Y" = "$_set_link" -o "Yes" = "$_set_link" -o "yes" = "$_set_link" ];then -# echononl " Create symlink.." -# rm -f /usr/local/dovecot -# ln -s dovecot-${_version} /usr/local/dovecot -# if [ "$?" = 0 ]; then -# echo -e "$rc_done" -# else -# echo -e "$rc_failed" -# fatal "Creating Symlink /usr/local/dovecot --> dovecot-${_version} /usr/local/dovecot failed" -# fi -#fi +blank_line + +_mode=644 +_owner="root" +_group="staff" +echononl " Set owner/group permissions all configuration files to 'root:staff'." +find "/usr/local/dovecot-${_version}/etc/dovecot" -type f -exec chown "${_owner}:${_group}" {} + +if ! $_failed ; then + echo -e "$rc_done" +else + echo -e "$rc_failed" + error "Setting the owner and group for the configuration files failed!" +fi + +echononl " Set permissions for all configuration files to '644'." +find "/usr/local/dovecot-${_version}/etc/dovecot" -type f -exec chmod "${_mode}" {} + +if ! $_failed ; then + echo -e "$rc_done" +else + echo -e "$rc_failed" + error "Setting permissions on configuration files failed!" +fi + +blank_line ## - Add a cronjob to check if certifice/key for dovecot service is-up-to-date