aboutsummaryrefslogtreecommitdiffstats
path: root/bin/mbsync_cron.sh
blob: e02bf93d5b8e41414548b0274b87aea67da5fc2a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/bin/sh
#
# Copyright (c) 2017 Aaron LI <aly@aaronly.me>
# 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
#

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} <account>"
    error ""
    error "available accounts:"
    error "  * aly"
    error "  * weitian"
    error "  * webmaster"
    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" | \
        gpg2 --sign --batch --no-tty --pinentry-mode error \
             --local-user ${key} -o /dev/null >/dev/null 2>&1
}


case "$1" in
    aly|weitian|webmaster)
        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} ..."
notify "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}!"