schleuder3/mail_to_listadmins.sh
2017-12-23 16:43:58 +01:00

821 lines
22 KiB
Bash
Executable File

#!/usr/bin/env bash
working_dir="$(dirname "$(realpath $0)")"
conf_file="${working_dir}/conf/mail_to_listadmins.conf"
_date="$(date +%Y-%m-%d-%H%M)"
log_dir="${working_dir}/log"
log_file="${log_dir}/mail_to_listadmins.${_date}.log"
schleuder_conf_file="/etc/schleuder/schleuder.yml"
LOCK_DIR="$(mktemp -d)"
err_msg="${LOCK_DIR}/err_msg.log"
#-----------------------------
# Some variables definitions
#-----------------------------
declare -a schleuder_domains_arr
declare -a schleuder_lists_arr
declare -a lists_done
declare -a lists_failed
declare -a lists_warn
#-----------------------------
# Base Function(s)
#-----------------------------
clean_up() {
# Perform program exit housekeeping
rm -rf $LOCK_DIR
exit $1
}
echo_log() {
echo "$*" >> "$log_file"
}
echo_log_done() {
echo "[ done ] $*" >> "$log_file"
}
echo_log_failed() {
echo "[ Error ] $*" >> "$log_file"
}
echo_log_skipped() {
echo "[ skipped ] $*" >> "$log_file"
}
echononl(){
if $terminal && $LOGGING ; 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[1mFatal\033[m ]: $*"
echo ""
echo -e " \033[31m\033[1mScript was interupted\033[m!"
else
echo " [ Fatal ]: $*"
echo ""
echo " Script was terminated...."
fi
echo ""
clean_up 1
}
error (){
echo ""
if $terminal ; then
echo -e " [ \033[31m\033[1mError\033[m ]: $*"
else
echo " [ Error ]: $*"
fi
echo ""
}
warn (){
echo ""
if $terminal ; then
echo -e " [ \033[33m\033[1mWarning\033[m ]: $*"
else
echo " [ Warning ]: $*"
fi
echo ""
}
info (){
echo ""
if $terminal ; then
echo -e " [ \033[32m\033[1mInfo\033[m ]: $*"
else
echo " [ Info ]: $*"
fi
echo ""
}
echo_done() {
if $terminal ; then
echo -e "\033[75G[ \033[32mdone\033[m ]"
else
echo " [ done ]"
fi
}
echo_failed(){
if $terminal && $LOGGING ; then
echo -e "\033[75G[ \033[1;31mfailed\033[m ]"
else
echo " [ failed ]"
fi
}
echo_skipped() {
if $terminal && $LOGGING ; then
echo -e "\033[75G[ \033[33m\033[1mskipped\033[m ]"
else
echo " [ skipped ]"
fi
}
function usage () {
if [ -n "$1" ];then
echo -e "\nError: $1"
fi
echo -e "
Usage: \033[1m$(basename $0) [-h] [<-s email-address>] [-f <message-file>]\033[m
$(basename $0) sends a message, reading from a given file, to all list administrators of
all supported schleuder3 lists.
The given message file (and within the containing text) must be UTF8 encoded. In the
message, you can use the parameter string '@LIST@' which will be replaced by the
full qualified list address for the appropriate list.
\033[1mNotice\033[m
The keyring of the user invoking this script (for now only user 'root' is possible)
must contain the private key for the given sender address. The script will ask you
for the concerning passwort.
The message file may contain string \033[1m@LIST@\033[m which will be replaced
by the list address.
Parameters not given on the commandline will be interactivly ask for.
Optinal Control Options:
-h
print that help text
-b Subject
subject name of the e-mail.
-p Password
Password for the secret key of the sender address. Its \033[1mhighly not recommend\033[m
to use this parameter, because the password is prompted out and maybe also
saved in the shell's history file. If omitting this option, the script will
ask for the password. The password will not be prompted at the commandline.
-s Sender Adrress
name of the sender e-mail address.
-f Message File
full qualified path tio the file containing the message
Example:
$(basename $0) -b "Listsoftware has changed" -f /root/msg_listadmin.txt -s support@so36.net
"
clean_up 2
}
# - See https://gist.github.com/epiloque/8cf512c6d64641bde388
parse_yaml() {
local prefix=$2
local s
local w
local fs
s='[[:space:]]*'
w='[a-zA-Z0-9_]*'
#fs="$(echo @|tr @ '\034')"
fs="$(echo @|tr @ '\034'|tr -d '\015')"
sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
-e "s|^\($s\)\($w\)$s[:-]$s\(.*\)$s\$|\1$fs\2$fs\3|p" "$1" |
awk -F"$fs" '{
indent = length($1)/2;
vname[indent] = $2;
for (i in vname) {if (i > indent) {delete vname[i]}}
if (length($3) > 0) {
vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
printf("%s%s%s=(\"%s\")\n", "'"$prefix"'",vn, $2, $3);
}
}' | sed 's/_=/+=/g'
}
if [[ ! -f "$schleuder_conf_file" ]]; then
fatal "Configuration file '$(basename ${schleuder_conf_file})' not found!"
else
eval $(parse_yaml "$schleuder_conf_file" "schleuder_" )
fi
# - Running in a terminal?
# -
if [[ -t 1 ]] ; then
terminal=true
else
terminal=false
fi
#-----------------------------
# Some tests
#-----------------------------
schleuder_user="$(stat -c '%U' "${schleuder_lists_dir}")"
schleuder_group="$(stat -c '%G' "${schleuder_lists_dir}")"
if ! id -u "$schleuder_user" > "$err_msg" 2>&1; then
error "$(cat "$err_msg")"
fatal "(Schleuder) User '$schleuder_user' does not exists"
fi
#-----------------------------
# Read default values from script configuration file
#-----------------------------
SENDER_ADDRESS=""
MESSAGE_FILE=""
SUBJECT=""
echo ""
echononl " Loading default Configuration values from $(basename ${conf_file}).."
if [[ ! -f "$conf_file" ]]; then
echo_skipped
else
source "${conf_file}" > $err_msg 2>&1
if [[ $? -eq 0 ]]; then
echo_done
else
echo_failed
fatal "$(cat $err_msg)"
fi
fi
[[ -n "$SENDER_ADDRESS" ]] && default_sender_address="$SENDER_ADDRESS"
[[ -n "$MESSAGE_FILE" ]] && default_orig_msg_file="$MESSAGE_FILE"
[[ -n "$SUBJECT" ]] && default_subject="$SUBJECT"
#-----------------------------
# Read Commandline Parameters
#-----------------------------
subject=""
sender_address=""
gpg_pw=""
orig_msg_file=""
while getopts b:hf:p:s: opt ; do
case $opt in
b) subject="$OPTARG"
;;
s) sender_address="$OPTARG"
;;
p) gpg_pw="$OPTARG"
;;
f) orig_msg_file="$OPTARG"
;;
h) usage
;;
*) usage
esac
done
if [[ -z "$orig_msg_file" ]] ; then
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Enter full qualified file name containing the message"
echo "you want to send to the list admins."
echo ""
orig_msg_file=""
if [[ -n "$default_orig_msg_file" ]]; then
echononl "Message file [$default_orig_msg_file]: "
read orig_msg_file
if [[ -z "$orig_msg_file" ]]; then
orig_msg_file="$default_orig_msg_file"
fi
else
while [[ -z "$orig_msg_file" ]] ; do
echononl "Message file: "
read orig_msg_file
if [[ -z "$orig_msg_file" ]]; then
echo -e "\n \033[33m\033[1mMessage file is required!\033[m\n"
fi
done
fi
fi
if [[ ! -f "$orig_msg_file" ]]; then
fatal "Message file \033[1m$orig_msg_file\033[m not found!"
fi
if [[ -z "$subject" ]]; then
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Enter the subject for sending the info e-mails."
echo ""
subject=""
if [[ -n "$default_subject" ]]; then
echononl "Subject [$default_subject]: "
read subject
if [[ -z "$subject" ]]; then
subject="$default_subject"
fi
else
while [[ -z "$subject" ]] ; do
echononl "Subject: "
read subject
if [[ -z "" ]]; then
echo -e "\n \033[33m\033[1mSender e-mail address is required!\033[m\n"
fi
done
fi
fi
# - To encode a header using this technique you must use this format:
# -
# - =?charset?encoding?encoded-text?=
# -
# - The encoding must be either B or Q, these mean base 64 and quoted-printable respectively.
# - You can read the RFC 1342 document for more information about how they work.
# -
subject_encoded=""
if echo "$subject" 2> /dev/null | file -i - | grep -i -q utf-8 ; then
subject_encoded="=?UTF-8?B?$(echo "$subject" | base64)?="
fi
if [[ -z "$sender_address" ]] ; then
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Enter the sender e-mail address you want to use for sending the info e-mails."
echo ""
sender_address=""
if [[ -n "$default_sender_address" ]]; then
echononl "Sender e-mail [$default_sender_address]: "
read sender_address
if [[ -z "$sender_address" ]]; then
sender_address="$default_sender_address"
fi
else
while [[ -z "$sender_address" ]] ; do
echononl "Sender e-mail: "
read sender_address
if [[ -z "" ]]; then
echo -e "\n \033[33m\033[1mSender e-mail address is required!\033[m\n"
fi
done
fi
fi
# - Secret Key for $sender_address must be present
# -
if ! gpg --list-secret-keys "${sender_address}" > /dev/null 2>&1 ; then
fatal "No secret key for id \"${sender_address}\" found"
fi
if [[ -z "$gpg_pw" ]]; then
_gpg_pw_1="X"
_gpg_pw_2="Y"
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Enter gpg password for ${sender_address}. The password will not"
echo "be shown at the command line"
echo ""
while [[ "$_gpg_pw_1" != "$_gpg_pw_2" ]] ; do
echononl "Password: "
read -s _gpg_pw_1
echo
if [ "X$_gpg_pw_1" = "X" ]; then
echo -e "\n \033[33m\033[1mPassword is required!\033[m\n"
continue
fi
echononl "Repeat password: "
read -s _gpg_pw_2
echo
if [ "X$_gpg_pw_2" = "X" ]; then
echo -e "\n \033[33m\033[1mPassword is required!\033[m\n"
continue
fi
if [ "$_gpg_pw_1" != "$_gpg_pw_2" ];then
echo -e "\n\t\033[33m\033[1mThe given passwords differs!\033[m\n"
else
gpg_pw=$_gpg_pw_1
fi
done
fi
gpg-connect-agent reloadagent /bye > /dev/null 2>&1
if ! $(echo "$gpg_pw" | gpg --trust-model=always --pinentry-mode loopback -o /dev/null --local-user $sender_address --passphrase $gpg_pw -as - > /dev/null 2>&1) ; then
fatal "Password does not match user id '${sender_address}'!"
fi
clear
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo ""
echo -e " \033[1;32mSettings for script \033[1m$(basename "$0")\033[m"
echo ""
echo -e " Sender Address...................: $sender_address"
echo -e " E-Mail Subject...................: $subject"
if [[ -n "$subject_encoded" ]] ; then
echo -e " E-Mail Subject (utf-8 encoded)...: $subject_encoded"
fi
echo -e " File containing the message......: $orig_msg_file"
echo ""
echo -e " Message: \n\n\033[1m$(cat "$orig_msg_file")\033[m\n"
echo ""
echo ""
echononl "Type upper case \033[1;37mYES\033[m to continue executing this script: "
read OK
if [[ "$OK" = "YES" ]] ; then
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo -e " \033[32m----------\033[m"
echo -e " \033[1mStarting Script to inform all Listadmins\033[m"
echo -e " \033[32m----------\033[m"
echo_log "# ----------------------------------------------------------------"
echo_log "# - Log output of script '$(basename $0)' at $_date"
echo_log "# ----------------------------------------------------------------"
echo_log ""
echo_log "----------"
echo_log "Settings for script $(basename "$0"):"
echo_log "----------"
echo_log ""
echo_log "Sender Address...................: $sender_address"
echo_log "E-Mail Subject...................: $subject"
if [[ -n "$subject_encoded" ]] ; then
echo_log "E-Mail Subject (utf-8 encoded)...: $subject_encoded"
fi
echo_log "File containing the message......: $orig_msg_file"
echo_log ""
echo_log "Message: "
echo_log "--"
echo_log "$(cat "$orig_msg_file")"
echo_log "--"
else
fatal "Abort by user request - Answer as not 'YES'"
fio ""
fi
echo ""
echononl " Create log directory"
if [[ ! -d "$log_dir" ]]; then
mkdir "$log_dir" > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
else
echo_done
fi
else
echo_skipped
fi
echo ""
echo ""
echo -e " \033[32m----------\033[m"
echo -e " \033[1mSummary Lists at $(hostname -f)\033[m"
echo -e " \033[32m----------\033[m"
echo ""
echo_log ""
echo_log ""
echo_log "----------"
echo_log "Summary Lists at $(hostname -f)"
echo_log "----------"
echo_log
# - Get Schleuder domains
# -
while IFS= read -r -d '' _dir ; do
schleuder_domains_arr+=("$(basename "$_dir")")
done < <(find "$schleuder_lists_dir" -mindepth 1 -maxdepth 1 -type d -print0)
echo_log "Schleuder Domains:"
echo -e " \033[32m\033[1mSchleuder Domains\033[m:"
for _domain in ${schleuder_domains_arr[@]} ; do
echo_log " $_domain"
echo " $_domain"
done
# - Get Schleuder lists
# -
for _domain in ${schleuder_domains_arr[@]} ; do
while IFS= read -r -d '' _list ; do
schleuder_lists_arr+=("$_domain:$(basename "$_list")")
done < <(find "${schleuder_lists_dir}/${_domain}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z )
done
echo_log ""
echo_log "Schleuder Lists"
echo -e "\n \033[32m\033[1mSchleuder Lists\033[m:"
for _val in "${schleuder_lists_arr[@]}" ; do
IFS=':' read -a _val_arr <<< "${_val}"
_domain="${_val_arr[0]}"
_list="${_val_arr[1]}"
if [[ -n "$_last_domain" ]] && [[ "$_last_domain" != "$_domain" ]] ; then
echo_log ""
echo ""
fi
echo_log " ${_domain}: ${_list}"
echo " ${_domain}: ${_list}"
_last_domain="$_domain"
done
echo ""
echo ""
echo -e " \033[32m----------\033[m"
echo -e " \033[1mMain part of script: inform list admins\033[m"
echo -e " \033[32m----------\033[m"
echo_log ""
echo_log ""
echo_log "----------"
echo_log "Main part of script: inform list admins"
echo_log "----------"
# - Export key of $sender_address into temporary directory ($LOCK_DIR)
# -
#echononl " Export public key '${sender_address}'.."
#gpg -a --export $sender_address > ${LOCK_DIR}/${sender_address}.asc 2> "$err_msg"
#if [[ $? -ne 0 ]]; then
# echo_log_failed "Export public key '${sender_address}'"
# echo_log "$(cat "$err_msg")"
# echo_failed
# error "$(cat "$err_msg")"
#else
# echo_done
# echo_log_done "Export public key '${sender_address}'"
#fi
for _val in "${schleuder_lists_arr[@]}" ; do
_missing_key=false
_message_prepared=false
_message_encrypted=false
IFS=':' read -a _val_arr <<< "${_val}"
_domain="${_val_arr[0]}"
_list="${_val_arr[1]}"
msg_file="${LOCK_DIR}/msg-${_list}-${_domain}.txt"
msg_file_encrypted="${LOCK_DIR}/msg_encrypted-${_list}-${_domain}.asc"
echo_log ""
echo_log "${_list}@${_domain}:"
echo -e "\n \033[32m\033[1m${_domain} - ${_list}\033[m:"
# - Copy original message in tmp folder ($LOCK_DIR)
# -
cp "$orig_msg_file" "$msg_file" > "$err_msg" 2>&1
if [[ $? -ne 0 ]]; then
echo_log "$(cat "$err_msg")"
error "$(cat "$err_msg")"
lists_failed+=("${_list}@$_domain")
continue
fi
echononl " Add List Key to keyring of 'root'"
if ! gpg -k "${_list}@$_domain" > /dev/null 2>&1 ; then
gpg --batch --yes --home "$_list_dir" -a --export ${_list}@$_domain | gpg --import
if [[ $? -ne 0 ]]; then
echo_log_failed "Add List Key to keyring of 'root'"
echo_failed
lists_failed+=("${_list}@$_domain")
continue
else
echo_log_done "Add List Key to keyring of 'root'"
echo_done
fi
else
echo_log_skipped "Add List Key to keyring of 'root'"
echo_skipped
fi
# - Check if gpg key of $sender_address is part of the keyring. Add key if missing
# -
_list_dir="${schleuder_lists_dir}/${_domain}/${_list}"
echononl " Adding key '$sender_address' to keyring.."
if ! gpg --home "$_list_dir" -k "$sender_address" > /dev/null 2>&1 ; then
#gpg --batch --yes --home "$_list_dir" --import /home/ckubu/support.so36.net.asc > "$err_msg" 2>&1
gpg --batch --yes -a --export "$sender_address" | gpg --home "$_list_dir" --import > "$err_msg" 2>&1
if [[ $? -ne 0 ]]; then
echo_log_failed "Adding key '$sender_address' to keyring"
echo_log "$(cat "$err_msg")"
echo_failed
error "$(cat "$err_msg")"
lists_failed+=("${_list}@$_domain")
continue
else
echo_log_done "Adding key '$sender_address' to keyring"
echo_done
fi
_missing_key=true
else
echo_log_skipped "Adding key '$sender_address' to keyring"
echo_skipped
fi
echononl " Adjust message file for list.."
perl -i -n -p -e "s/\@LIST\@/${_list}\@${_domain}/g" "$msg_file" > "$err_msg" 2>&1
if [[ $? -ne 0 ]]; then
echo_log_failed "Adjust message file for list"
echo_log "$(cat "$err_msg")"
echo_failed
error "$(cat "$err_msg")"
lists_failed+=("${_list}@$_domain")
else
echo_log_done "Adjust message file for list"
echo_done
_message_prepared=true
fi
echononl " Encrypt and sign message for list.."
if $_message_prepared ; then
gpg --trust-model=always --pinentry-mode loopback --passphrase $gpg_pw -a -se -u "${sender_address}" -r "${_list}@$_domain" -o "${msg_file_encrypted}" "${msg_file}" > "$err_msg" 2>&1
if [[ $? -ne 0 ]]; then
echo_log_failed "Encrypt and sign message for list"
echo_log "$(cat "$err_msg")"
echo_failed
error "$(cat "$err_msg")"
lists_failed+=("${_list}@$_domain")
else
echo_log_done "Encrypt and sign message for list"
echo_done
_message_encrypted=true
fi
fi
if $_message_encrypted ; then
boundery_1="$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 33 | head -n 1)"
boundery_2="$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 33 | head -n 1)"
message_id="$(cat /dev/urandom | tr -dc 'a-f0-9' | fold -w 8 | head -n 1)-$(cat /dev/urandom | tr -dc 'a-f0-9' | fold -w 4 | head -n 1)-$(cat /dev/urandom | tr -dc 'a-f0-9' | fold -w 4 | head -n 1)-$(cat /dev/urandom | tr -dc 'a-f0-9' | fold -w 4 | head -n 1)-$(cat /dev/urandom | tr -dc 'a-f0-9' | fold -w 12 | head -n 1)@so36.net"
if [[ -n "$subject_encoded" ]] ; then
subject="$subject_encoded"
fi
cat <<EOF > "${LOCK_DIR}/e-mail-${_list}-${_domain}.txt"
Content-Type: multipart/mixed; boundary="$boundery_1";
protected-headers="v1"
From: so36.NET <support@so36.net>
To: ${_list}-owner@$_domain
Date: $(date +"%a, %d %b %Y %H:%M:%S %z")
Message-ID: <$message_id>
Subject: $subject
--$boundery_1
Content-Type: multipart/mixed; boundary="$boundery_2"
--$boundery_2
Content-Type: text/plain; charset=utf-8
Content-Language: de-DE
Content-Transfer-Encoding: quoted-printable
EOF
cat "$msg_file_encrypted" >> "${LOCK_DIR}/e-mail-${_list}-${_domain}.txt"
cat <<EOF >> "${LOCK_DIR}/e-mail-${_list}-${_domain}.txt"
--$boundery_2--
--$boundery_1--
EOF
echononl " Send info e-mail to list owner .."
cat "${LOCK_DIR}/e-mail-${_list}-${_domain}.txt" | su schleuder -c"/usr/local/bin/schleuder work ${_list}-owner@$_domain" -s /bin/bash
if [[ $? -ne 0 ]]; then
echo_log_failed "Send info e-mail to list owner"
echo_failed
lists_failed+=("${_list}@$_domain")
else
echo_log_done "Send info e-mail to list owner"
echo_done
lists_done+=("${_list}@$_domain")
fi
fi
echononl " Removing key of '$sender_address' from list keyring.."
if $_missing_key ; then
gpg --batch --yes --home "$_list_dir" --delete-key "$sender_address" > "$err_msg" 2>&1
if [[ $? -ne 0 ]]; then
echo_log_failed "Removing key of '$sender_address' from list keyring"
echo_log "$(cat "$err_msg")"
echo_failed
warn "$(cat "$err_msg")"
lists_warn+=("${_list}@$_domain")
else
echo_log_done "Removing key of '$sender_address' from list keyring"
echo_done
fi
echononl " Set ownerchip of list keyring back to '${schleuder_user}'"
chown ${schleuder_user}:${schleuder_group} $_list_dir/pubring.* > "$err_msg" 2>&1
if [[ $? -ne 0 ]]; then
echo_log_failed "Set ownerchip of list keyring back to '${schleuder_user}'"
echo_log "$(cat "$err_msg")"
echo_failed
warn "$(cat "$err_msg")"
lists_warn+=("${_list}@$_domain")
else
echo_log_done "Set ownerchip of list keyring back to '${schleuder_user}'"
echo_done
fi
else
echo_log_skipped "Removing key of '$sender_address' from list keyring"
echo_skipped
fi
done
# - Clear cached gpg password
# -
echo ""
echo ""
echo_log ""
echo_log ""
echononl " Clear cached gpg password.."
gpg-connect-agent reloadagent /bye > "$err_msg" 2>&1
if [[ $? -ne 0 ]]; then
echo_log_failed "Clear cached gpg password"
echo_log "$(cat "$err_msg")"
echo_failed
error "$(cat "$err_msg")"
else
echo_log_done "Clear cached gpg password"
echo_done
fi
echononl " Archive msg file.."
mv "$orig_msg_file" "${orig_msg_file}.${_date}.sent"
if [[ $? -ne 0 ]]; then
echo_log_failed "Archive msg file"
echo_log "$(cat "$err_msg")"
echo_failed
error "$(cat "$err_msg")"
else
echo_log_done "Archive msg file"
echo_done
fi
echo ""
echo ""
echo -e " \033[32m----------\033[m"
echo -e " \033[1mStatistics \033[m"
echo -e " \033[32m----------\033[m"
echo ""
echo -e " ${#lists_done[@]} lists successfully informed"
echo -e " ${#lists_warn[@]} lists with warnings"
echo -e " ${#lists_failed[@]} lists failed"
echo_log ""
echo_log ""
echo_log "----------"
echo_log "Statistics"
echo_log "----------"
echo_log
echo_log "${#lists_done[@]} lists successfully informed"
echo_log "${#lists_warn[@]} lists with warnings"
echo_log "${#lists_failed[@]} lists failed"
echo_log
if [[ ${#lists_failed[@]} -gt 0 ]]; then
echo_log "Listadmin(s) not informed:"
echo -e "\n \033[1mListadmin(s) not informed:\033[m"
for _list in "${lists_failed[@]}" ; do
echo -e " $_list"
echo_log " $_list"
done
echo_log
info "See also log file: $log_file"
else
info "See also script output at log file: $log_file"
fi
echo ""
clean_up 0