diff --git a/conf/maildir-last-change.conf.sample b/conf/maildir-last-change.conf.sample new file mode 100644 index 0000000..782c7ef --- /dev/null +++ b/conf/maildir-last-change.conf.sample @@ -0,0 +1,22 @@ +# ----------------------------------------------------------- +# - Parameter Settings for script 'maildir-last-change.conf'. +# ----------------------------------------------------------- + +# MAILBOX_BASE_DIR +# +# Base directory containing the all the domains within their +# mailboxes +# +# Defaults to: +# MAILBOX_BASE_DIR="/var/vmail" +# +#MAILBOX_BASE_DIR="/var/vmail" + +# DST_DIR +# +# Directory containing the created statistic files. +# +# Defaults to: +# DST_DIR="/var/MAIL-STATS/LAST-CHANGE" +# +#DST_DIR="/var/MAIL-STATS/LAST-CHANGE" diff --git a/maildir-last-change.sh b/maildir-last-change.sh new file mode 100755 index 0000000..5e0e11f --- /dev/null +++ b/maildir-last-change.sh @@ -0,0 +1,327 @@ +#!/usr/bin/env bash + +export LC_ALL=en_US.utf8 + +script_name="$(basename $(realpath $0))" +working_dir="$(dirname $(realpath $0))" +conf_file="${working_dir}/conf/${script_name%%.*}.conf" + +LOCK_DIR="/tmp/dovecot_last_change.LOCK" +error_log="${LOCK_DIR}/error.log" + +_CACHE_FILE="${LOCK_DIR}/tmp_last_change" + + + + +# ------------- +# --- Some defaut values +# ------------- + +DEFAULT_MAILBOX_BASE_DIR="/var/vmail" +DEFAULT_DST_DIR="/var/MAIL-STATS/LAST-CHANGE" +DEFAULT_DOMAIN="*" + +DEFAULT_USER="*" + + + +# ------------- +# --- Some functions +# ------------- + + +usage() { + + + [[ -n "$1" ]] && error "$1" + + + [[ $terminal ]] && echo -e " +\033[1mUsage:\033[m + + $(basename $0) [-d ] + +\033[1mDescription\033[m + + Script determins the 'last change' time of maildirs using dovecots 'dovecot.index.log' + for each mailbox of a domain. If no domain was given at the command line, statistics + is written for all mailboxes of all available domains. + +\033[1mOptions\033[m + + -d + The domain for which the 'last change' statistic is written. The default is to + write statistics for all available mail domains. + +\033[1mFiles\033[m + + $conf_file: Configuration file + +\033[1mExample:\033[m + + Write statistics for domain mail36.net + + $(basename $0) .. + +" + + clean_up 1 + +} + + +clean_up() { + + # Perform program exit housekeeping + rm -rf "$LOCK_DIR" + blank_line + exit $1 +} + +echononl(){ + if $terminal ; then + echo X\\c > /tmp/shprompt$$ + if [[ $(wc -c /tmp/shprompt$$ | awk '{print $1}') -eq 1 ]]; then + echo -e -n " $*\\c" 1>&2 + else + echo -e -n " $*" 1>&2 + fi + rm /tmp/shprompt$$ + fi +} + +fatal(){ + echo "" + if $terminal ; then + echo -e " [ \033[31m\033[1mError\033[m ]: $*" + echo "" + echo -e "\033[15G\033[31m\033[1mScript was interupted\033[m!" + else + echo " [ Fatal ]: $*" + echo "" + echo " Script was terminated...." + fi + echo "" + clean_up 1 +} + +warn (){ + if $terminal ; then + blank_line + echo -e " [ \033[33m\033[1mWarn\033[m ] $*" + blank_line + fi +} + +info (){ + if $terminal ; then + blank_line + echo -e " [ \033[32m\033[1mInfo\033[m ] $*" + blank_line + fi +} + +echo_done() { + if $terminal ; then + echo -e "\033[75G[ \033[32mdone\033[m ]" + fi +} +echo_failed(){ + if $terminal ; then + echo -e "\033[75G[ \033[1;31mfailed\033[m ]" + fi +} +echo_skipped() { + if $terminal ; then + echo -e "\033[75G[ \033[37m\033[1mskipped\033[m ]" + fi +} +echo_wait(){ + if $terminal ; then + echo -en "\033[75G[ \033[5m\033[1m...\033[m ]" + fi +} + +blank_line() { + if $terminal ; then + echo "" + fi +} + +# Check if a given array (parameter 2) contains a given string (parameter 1) +# +containsElement () { + local e + for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done + return 1 +} + + +# ------------- +# - Job is already running? +# ------------- + +# - If job already runs, stop execution.. +# - +if mkdir "$LOCK_DIR" 2> /dev/null ; then + + ## - Remove lockdir when the script finishes, or when it receives a signal + trap clean_up SIGHUP SIGINT SIGTERM + +else + + datum="$(date +"%d.%m.%Y %H:%M")" + + msg="A previos instance of \"${script_name}\" seems already be running." + + blank_line + + if $terminal ; then + echo -e " [ \033[31m\033[1mError\033[m ]: $msg" + echo "" + echo -e "\033[15G\033[31m\033[1mScript was interupted\033[m!" + else + echo " [ Fatal ]: $msg" + echo "" + echo " Script was terminated...." + fi + echo "" + + exit 1 + +fi + + + +# ------------- +# --- Check some prerequisites +# ------------- + +# - Running in a terminal? +# - +if [[ -t 1 ]] ; then + terminal=true +else + terminal=false +fi + + +# ========== +# - Begin Main Script +# ========== + +# ---------- +# - Headline +# ---------- + +if $terminal ; then + echo "" + echo -e "\033[1m----------\033[m" + echo -e "\033[32m\033[1mRunning script \033[m\033[1m$script_name\033[32m .. \033[m" + echo -e "\033[1m----------\033[m" +fi + + +# ---------- +# - Read Configurations from file '$conf_file' +# ---------- + +if [[ -f "$conf_file" ]]; then + source "$conf_file" +else + warn "No configuration file '$conf_file' present.\n + Loading default values.." +fi + +[[ -n "${MAILBOX_BASE_DIR}" ]] || MAILBOX_BASE_DIR="${DEFAULT_MAILBOX_BASE_DIR}" +[[ -n "${DST_DIR}" ]] || DST_DIR="${DEFAULT_DST_DIR}" + + +# ---------- +# - Read commandline parameter +# ---------- + +while getopts d:h opt ; do + case $opt in + d) DOMAIN="$OPTARG" + ;; + h) usage + ;; + \?) usage ;; + esac +done + +[[ -n "${DOMAIN}" ]] || DOMAIN="*" +USER="*" + + +echo -n '' > $_CACHE_FILE +chmod 600 $_CACHE_FILE + +declare -a _domain_arr=() + + +blank_line + +echononl "Create Directory '${DST_DIR}'.." +if [[ ! -d "$DST_DIR" ]] ; then + mkdir -p "$DST_DIR" > $error_log 2>&1 + if [[ $? -eq 0 ]]; then + echo_done + else + echo_failed + error "$(cat "$error_log")" + fi +else + echo_skipped +fi + + +echononl "Determin last change time for mailboxes.." +echo_wait +for _index_log in $(ls ${MAILBOX_BASE_DIR}/${DOMAIN}/${USER}/Maildir/dovecot.index.log); do + + LAST_CHANGE="$(stat $_index_log | grep 'Change: ' | cut -d' ' -f2)" + DOMAIN="$(echo $_index_log | cut -d/ -f4)" + USER="$(echo $_index_log | cut -d/ -f5)" + echo "$LAST_CHANGE ${USER}@${DOMAIN}" >> $_CACHE_FILE + + if ! containsElement "$DOMAIN" "${_domain_arr[@]}" ; then + _domain_arr+=("$DOMAIN") + fi + +done; +echo_done + +echononl "Write down over all statistic file .." +if [[ ${#_domain_arr[@]} -gt 1 ]]; then + cat $_CACHE_FILE | sort -n > "${DST_DIR}/00-all-domains.stat" 2> "$error_log" + if [[ $? -eq 0 ]]; then + echo_done + else + echo_failed + error "$(cat "$error_log")" + fi +else + echo_skipped +fi + +echononl "Write down statistic files per domain .." +echo_wait +_failed=false +for _domain in "${_domain_arr[@]}" ; do + cat "${DST_DIR}/00-all-domains.stat" | grep "@$_domain" > "${DST_DIR}/${_domain}.stat" 2> "$error_log" + if [[ $? -ne 0 ]]; then + _failed=true + fi +done +if $_failed ; then + echo_failed +else + echo_done +fi + +info "Statistic file(s) stored at directory '${DST_DIR}/'" + +clean_up 0;