#!/bin/sh # # Copyright (c) 2017 Aaron LI # MIT license # # Get new mails and sync IMAP folders using `mbsync` with `cron`. # # Since the passwords are managed using `pass` which encrypts them using # `gpg`, therefore, `gpg-agent` will be periodically triggered to ask user # for the passphrase to decrypt the stored passwords, which is annoying # for the cron tasks. # # Workaround the `gpg-agent` asking for passphrase by testing its current # status about the cached passphrase, i.e., with *pinentry* disabled # (by passing the `--pinentry-mode error` to `gpg`), invoke `gpg` to try # to sign a message, if it succeed, then the necessary passphrase has # already been cached by `gpg-agent`. # # Reference: # * Programmatically determine if gpg-agent will ask for passphrase # https://superuser.com/a/1212720/731908 # # Aaron LI # 2017-05-28 # # 2017-10-25: Update "webmaster" to "postmaster" # set -e umask 027 # Workaround to make `notify-send` work with cron # Credit: https://stackoverflow.com/a/16520076 export DISPLAY=:0 export XAUTHORITY="${HOME}/.Xauthority" PROG="${0##*/}" LOGFILE="/dev/null" # The GPG key used by `pass` GPG_KEY="aly@aaronly.me" # Command to send notification NOTIFY_CMD="notify-send" error() { echo "$*" >&2 } log() { echo "[$(date --iso-8601=seconds)] $*" >> ${LOGFILE} } exists() { command -v "$1" >/dev/null 2>&1 } # Check if a process id (PID) exists # Credit: https://stackoverflow.com/a/3044045 is_running() { kill -0 "$1" >/dev/null 2>&1 } notify() { local message="$1" if exists ${NOTIFY_CMD}; then command ${NOTIFY_CMD} ${PROG} "${message}" fi } usage() { error "usage: ${PROG} " error "" error "available accounts:" error " * aly" error " * weitian" error " * postmaster" error " * autistici" error " * lavabit" error " * outlook-aly" error " * outlook-li" error " * gmail-aly" error " * gmail-li" error " * sjtu" error " * foxmail" } # Check whether `gpg-agent` already cached the needed passphrase, # if return 0 (i.e., success), then the passphrase is already cached, # then `pass` can decrypt the password without triggering `gpg-agent` # to ask user for the passphrase. check_cached_passphrase() { local key="$1" echo "test" | \ gpg --sign --batch --no-tty --pinentry-mode error \ --local-user ${key} -o /dev/null >/dev/null 2>&1 } case "$1" in aly|weitian|postmaster) ACCOUNT="$1" ;; autistici) ACCOUNT="$1" ;; lavabit) ACCOUNT="$1" ;; outlook-aly|outlook-li) ACCOUNT="$1" ;; gmail-aly|gmail-li) ACCOUNT="$1" ;; sjtu) ACCOUNT="$1" ;; foxmail) ACCOUNT="$1" ;; -h|--help) usage exit 1 ;; *) error "Invalid account name!" usage exit 1 ;; esac # PID file for `mbsync`, which may just hang and lock the mailbox PIDFILE="${HOME}/.cache/mbsync.${ACCOUNT}.pid" # Log file to record the sync information LOGFILE="${HOME}/.cache/mbsync.${ACCOUNT}.log" [ ! -f ${LOGFILE} ] && touch ${LOGFILE} log "-----------------------------------" if ! check_cached_passphrase ${GPG_KEY}; then log "GPG passphrase not cached! Skip sync mail." notify "GPG passphrase not cached! Skip sync mail." exit 2 fi if [ -f "${PIDFILE}" ]; then PID=$(cat ${PIDFILE}) if is_running ${PID} && ! kill ${PID} >/dev/null 2>&1; then log "Cannot kill process: ${PID}" notify "Cannot kill process: ${PID}" fi fi log "Sync mail for account: ${ACCOUNT} ..." mbsync -V "${ACCOUNT}" >>${LOGFILE} 2>&1 & #sleep 10 & PID=$! echo ${PID} > ${PIDFILE} wait ${PID} rm ${PIDFILE} log "Finish syncing mail for account: ${ACCOUNT}!" notify "Finish syncing mail for account: ${ACCOUNT}!"