#!/bin/bash
#
# This script performs a backup of the mailbox list of a cyrus-imapd
# instance which can be used to recreate mailboxes.db.
# Restore is done using ctl_mboxlist after uncompressing the file.

# fallback to su if runuser not available
if [ -x /sbin/runuser ]; then
  RUNUSER=runuser
else
  RUNUSER=su
fi

# instance config
CYRUSCONF=/etc/cyrus${INSTANCE}.conf
IMAPDCONF=/etc/imapd${INSTANCE}.conf

# make sure what we have is a valid instance
# and that config files are present
if [ -n "$INSTANCE" ]; then
  [ -L /etc/rc.d/init.d/cyrus-imapd${INSTANCE} ] || exit 0
fi
[ -f $CYRUSCONF ] || exit 0
[ -f $IMAPDCONF ] || exit 0

# source custom configuration
if [ -f /etc/sysconfig/cyrus-imapd${INSTANCE} ]; then
  . /etc/sysconfig/cyrus-imapd${INSTANCE}
fi

[ -x /usr/lib64/cyrus-imapd/ctl_mboxlist ] || exit 0

# expand_config <path>
# handle "@include" sections from imapd style config file
expand_config() {
  while read line; do
    if printf "%s\n" "${line}" | grep -q '^@include:'; then
      expand_config "$( printf "%s\n" "${line}" | cut -d : -f 2- | sed -e 's/^[\t ]*//' )"
    else
      printf "%s\n" "${line}"
    fi
  done < $1
}

# get_config <config> [<default>]
# extracts config option from config file
get_config() {
  searchstr=$1
  if config="$(expand_config $IMAPDCONF | egrep "^${searchstr}:")"; then
    printf "%s\n" "$config" | cut -d : -f 2- | sed -e 's/^[\t ]*//'
  else
    echo $2
  fi
}

# expands vars like {configdirectory}
expand_vars() {
  line="$@"
  line="${line//\{configdirectory\}/${configdirectory}}"
  echo "$line"
}

# db.cfg path
data_dir=/usr/share/cyrus-imapd/slack
db_cfg=${data_dir}/db.cfg

# source builtin config options if any
[ -f $db_cfg ] && . $db_cfg

configdirectory="$(get_config configdirectory /var/lib/imap${INSTANCE})"
mboxlist_db_path="$(get_config mboxlist_db_path ${configdirectory}/mailboxes.db)"
BACKDIR="${configdirectory}/backup"
MBOXLIST="${BACKDIR}/mboxlist"
ROTATE=6

# expand {configdirectory} in paths
mboxlist_db_path="$(expand_vars "$mboxlist_db_path")"

# exit if mboxlist doesn't exist
[ -f "$mboxlist_db_path" ] || exit 0

# error exit if backup directory missing, no output
[ -d "$BACKDIR" ] || exit 1

# rotate mailbox lists
for ((CNT=$ROTATE - 1; CNT > 0; CNT--)); do
  [ -f "${MBOXLIST}.${CNT}.gz" ] && mv -f "${MBOXLIST}.${CNT}.gz" "${MBOXLIST}.$(( $CNT + 1 )).gz"
done
[ -f "${MBOXLIST}.gz" ] && mv -f "${MBOXLIST}.gz" "${MBOXLIST}.1.gz"

# export mailboxes.db
$RUNUSER - cyrus -s /bin/bash -c "umask 0077 < /dev/null ; /usr/lib64/cyrus-imapd/ctl_mboxlist -C $IMAPDCONF -d | gzip > ${MBOXLIST}.gz"
