#!/bin/bash
# Makes FreeSWITCH-created mailbox directories group-writable; takes no input, every value is fixed here.
# Compiled by handlebars at build time, so a literal double brace anywhere in this file breaks the build.

set -euo pipefail

readonly OWNER_ACCOUNT='freeswitch'
readonly OWNER_GROUP='freeswitch'
readonly EXTERNAL_ROOT='/srv/unifi-talk/voicemail'
readonly INTERNAL_ROOT='/data/unifi-talk/voicemail'
readonly DOMAIN_DIR_NAME='talk.com'
readonly TARGET_MODE='770'

# exit codes the caller logs
readonly E_USAGE=2
readonly E_ACCOUNT=3
readonly E_CHMOD=4

FIXED=0
FAILED=0

fail() {
  echo "$2" >&2
  exit "$1"
}

# stat does not dereference, so a root that is a symlink reads as a link and is skipped
is_real_dir() {
  local kind

  kind=$(stat -c '%F' -- "$1" 2>/dev/null) || return 1

  [ "$kind" = 'directory' ]
}

# find -P never follows links and -maxdepth 1 lists only the domain and its direct children. One pass, as a
# stat per mailbox would not fit the caller's timeout; a listing error is not a failure, only a chmod is
fix_root() {
  local root="$1" owner group target

  is_real_dir "$root" || return 0

  while IFS= read -r -d '' owner && IFS= read -r -d '' group && IFS= read -r -d '' target; do
    [ "$owner" = "$OWNER_ACCOUNT" ] || continue
    [ "$group" = "$OWNER_GROUP" ] || continue

    # a failed chmod must not stop the rest, and its message names the entry, so it is dropped
    if chmod "$TARGET_MODE" -- "$target" 2>/dev/null; then
      FIXED=$(( FIXED + 1 ))
    else
      FAILED=$(( FAILED + 1 ))
    fi
  done < <(find -P "$root/$DOMAIN_DIR_NAME" -maxdepth 1 -type d ! -perm -020 -printf '%u\0%g\0%p\0' 2>/dev/null)
}

[ "$#" -eq 0 ] || fail "$E_USAGE" 'takes no arguments'

account=$(id -un 2>/dev/null) || account=''
[ "$account" = "$OWNER_ACCOUNT" ] || fail "$E_ACCOUNT" 'not running as the mailbox owner account'

fix_root "$EXTERNAL_ROOT"
fix_root "$INTERNAL_ROOT"

printf '%s\n' "$FIXED"

[ "$FAILED" -eq 0 ] || fail "$E_CHMOD" 'some directories could not be changed'
