355 lines
16 KiB
Bash
Executable File
355 lines
16 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
command -V gpg >/dev/null 2>&1 && GPG="gpg" || GPG="gpg2"
|
|
[ -z ${PASSWORD_STORE_DIR+x} ] && PASSWORD_STORE_DIR="$HOME/.password-store"
|
|
[ -r "$PASSWORD_STORE_DIR/.gpg-id" ] &&
|
|
"$GPG" --list-secret-keys $(cat "$PASSWORD_STORE_DIR/.gpg-id") >/dev/null 2>&1 || {
|
|
printf "\`pass\` must be installed and initialized to encrypt passwords.\\nBe sure it is installed and run \`pass init <yourgpgemail>\`.\\nIf you don't have a GPG public private key pair, run \`%s --full-gen-key\` first.\\n" "$GPG"
|
|
exit
|
|
}
|
|
! command -v mbsync >/dev/null && printf "\`mbsync (isync package)\` must be installed to run mutt-wizard.\\n" && exit
|
|
|
|
prefix="/usr/local"
|
|
muttdir="$HOME/.config/mutt" # Main mutt config location
|
|
accdir="$muttdir/accounts" # Directory for account settings
|
|
maildir="$HOME/.local/share/mail" # Location of mail storage
|
|
namere="^[a-z_][a-z0-9_-]*$" # Regex to ensure viable username
|
|
emailre=".\+@.\+\\..\+" # Regex to confirm valid email address
|
|
muttshare="$prefix/share/mutt-wizard"
|
|
mbsyncrc="$HOME/.mbsyncrc"
|
|
mwconfig="$muttshare/mutt-wizard.muttrc"
|
|
cachedir="$HOME/.cache/mutt-wizard"
|
|
muttrc="$muttdir/muttrc"
|
|
msmtprc="$HOME/.config/msmtp/config"
|
|
ssltype="IMAPS" # This is later changed to `None` later in the script if using Protonmail
|
|
|
|
for x in "/etc/ssl/certs/ca-certificates.crt" "/etc/pki/tls/certs/ca-bundle.crt" "/etc/ssl/ca-bundle.pem" "/etc/pki/tls/cacert.pem" "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" "/etc/ssl/cert.pem" "/usr/local/share/ca-certificates/"
|
|
do
|
|
[ -f "$x" ] && sslcert="$x" && break
|
|
done || { echo "CA Certificate not found. Please install one or link it to /etc/ssl/certs/ca-certificates.crt" && exit 1 ;}
|
|
|
|
getaccounts() { accounts="$(find "$accdir" -type f | grep -o "[0-9]-.*.muttrc" | sed "s/-/: /;s/\..*//" | sort -n)" ;}
|
|
list() { getaccounts && [ -n "$accounts" ] && echo "$accounts" ;}
|
|
|
|
getprofiles() { \
|
|
unset msmtp_header msmtp_profile mutt_profile mbsync_profile
|
|
printf "Creating profiles for \`%s\`..." "$title"
|
|
msmtp_header="defaults
|
|
auth on
|
|
tls on
|
|
tls_trust_file $sslcert
|
|
logfile ~/.config/msmtp/msmtp.log
|
|
"
|
|
msmtp_profile="account $title
|
|
host $smtp
|
|
port $sport
|
|
from $fulladdr
|
|
user $login
|
|
passwordeval \"pass mutt-wizard-$title\"
|
|
$starttlsoff
|
|
"
|
|
mbsync_profile="IMAPStore $title-remote
|
|
Host $imap
|
|
Port $iport
|
|
User $login
|
|
PassCmd \"pass mutt-wizard-$title\"
|
|
AuthMechs LOGIN
|
|
SSLType $ssltype
|
|
CertificateFile $sslcert
|
|
|
|
MaildirStore $title-local
|
|
Subfolders Verbatim
|
|
Path ~/.local/share/mail/$title/
|
|
Inbox ~/.local/share/mail/$title/INBOX
|
|
Flatten .
|
|
|
|
Channel $title
|
|
Expunge Both
|
|
Master :$title-remote:
|
|
Slave :$title-local:
|
|
Patterns * !\"[Gmail]/All Mail\"
|
|
Create Both
|
|
SyncState *
|
|
MaxMessages $maxmes
|
|
ExpireUnread no
|
|
# End profile
|
|
"
|
|
|
|
if [ "$accounttype" = "offline" ]; then
|
|
mutt_profile="# vim: filetype=neomuttrc
|
|
# muttrc file for account $title
|
|
set realname = \"$realname\"
|
|
set from = \"$fulladdr\"
|
|
set sendmail = \"msmtp -a $title\"
|
|
alias me $realname <$fulladdr>
|
|
set folder = \"$maildir/$title\"
|
|
set header_cache = $cachedir/$title/headers
|
|
set message_cachedir = $cachedir/$title/bodies
|
|
set mbox_type = Maildir
|
|
|
|
set crypt_autosign = yes
|
|
set crypt_opportunistic_encrypt = yes
|
|
set pgp_self_encrypt = yes
|
|
set pgp_default_key = $keyid
|
|
|
|
bind index,pager gg noop
|
|
bind index,pager g noop
|
|
bind index,pager M noop
|
|
bind index,pager C noop
|
|
bind index gg first-entry
|
|
macro index o \"<shell-escape>mbsync -V $title<enter>\" \"run mbsync to sync $title\"
|
|
unmailboxes *
|
|
"
|
|
else
|
|
mutt_profile="# vim: filetype=neomuttrc
|
|
# muttrc file for account $title
|
|
set realname = \"$realname\"
|
|
set from = \"$fulladdr\"
|
|
set sendmail = \"msmtp -a $title\"
|
|
alias me $realname <$fulladdr>
|
|
set folder = \"imaps://$login@$imap:$iport\"
|
|
set imap_user = \"$login\"
|
|
set header_cache = $cachedir/$title/headers
|
|
set message_cachedir = $cachedir/$title/bodies
|
|
set imap_pass = \"\`pass mutt-wizard-$title\`\"
|
|
|
|
set crypt_autosign = yes
|
|
set crypt_opportunistic_encrypt = yes
|
|
set pgp_self_encrypt = yes
|
|
set pgp_default_key = $keyid
|
|
|
|
|
|
set mbox_type = Maildir
|
|
set ssl_starttls = yes
|
|
set ssl_force_tls = yes
|
|
|
|
bind index,pager gg noop
|
|
bind index,pager g noop
|
|
bind index,pager M noop
|
|
bind index,pager C noop
|
|
bind index gg first-entry
|
|
unmailboxes *
|
|
"
|
|
fi
|
|
printf "DONE.\\n"
|
|
}
|
|
|
|
askinfo() { \
|
|
printf "Insert the \033[31memail address\033[0m that you want to autoconfigure for mutt/mbsync\\n\tEmail: \033[36m"
|
|
read -r fulladdr
|
|
keyid=$("$GPG" --list-keys --with-colons "$fulladdr" | awk -F: '/^pub:/ { print $5 }')
|
|
printf "\033[0m"
|
|
while ! echo "$fulladdr" | grep "$emailre" >/dev/null; do
|
|
printf "That is not a valid \033[31memail address\033[0m, please retype the desired email.\\n\\nEmail: \033[36m\t"
|
|
read -r fulladdr
|
|
printf "\033[0m"
|
|
done
|
|
domain="$(echo "$fulladdr" | sed "s/.*@//")"
|
|
search_query=$domain
|
|
case "$domain" in
|
|
protonmail.com|protonmail.ch|pm.me)
|
|
search_query='protonmail.com' ;;
|
|
*)
|
|
while : ; do
|
|
printf "\nIs your email hosted with Protonmail? [yes/no] "
|
|
read -r is_protonmail
|
|
case $is_protonmail in
|
|
[Yy][Ee][Ss]) search_query='protonmail.com' && break;;
|
|
[Nn][Oo]) break;;
|
|
*) printf 'Please answer Yes or No'
|
|
esac; done;
|
|
esac
|
|
printf "\\nSearching for \033[32m%s\033[0m in \033[34m\`domains.csv\`\033[0m..." "$domain"
|
|
serverinfo="$(grep "^$search_query" "$muttshare/domains.csv" 2>/dev/null)"
|
|
if [ -z "$serverinfo" ]; then
|
|
printf "Your email domain is not in mutt-wizard's database yet.\\nmutt-wizard will still autoconfigure everything, but you will have to manually type in your service's IMAP and SMTP server information.\\nYou can usually quickly find this by internet searching for it.\\n"
|
|
printf "Insert the IMAP server for your email provider (excluding the port number)\\n\033[36m\t"
|
|
read -r imap
|
|
printf "\033[0mWhat is your server's IMAP port number? (Usually something like 993)\\n\033[36m\t"
|
|
read -r iport
|
|
printf "\033[0mInsert the SMTP server for your email provider (excluding the port number)\\n\033[36m\t"
|
|
read -r smtp
|
|
printf "\033[0mWhat is your server's SMTP port number? (Usually 587 or 465)\\n\033[36m\t"
|
|
read -r sport
|
|
printf "\033[0m\\nGreat! If you want to be helpful, copy the line below and you can add it to the \`domains.csv\` file on Github.\\nThis will make things easier for others who use your email provider.\\n\\n%s,%s,%s,%s,%s\\n\\nAlthough be sure to test to see if these settings work first! ;-)\\n" "$domain" "$imap" "$iport" "$smtp" "$sport"
|
|
else
|
|
IFS=, read -r service imap iport smtp sport <<EOF
|
|
$serverinfo
|
|
EOF
|
|
printf "\\n\033[3;33mCongrats!\033[0m Server info has automatically been found, so you won't have to look anything up!\\n\t\033[1mIMAP server\033[0m: %s\\n\t\033[1mIMAP port\033[0m: %s\\n\t\033[1mSMTP server\033[0m: %s\\n\t\033[1mSMTP port\033[0m: %s\\nThis data will be used by the wizard.\\n" "$imap" "$iport" "$smtp" "$sport"
|
|
case "$service" in
|
|
gmail.com) printf "\033[31mREMEMBER: Gmail users must enable \"less secure\" (third-party) applications first for the sync to work:\\nhttps://support.google.com/accounts/answer/6010255\\n\033[0m" ;;
|
|
protonmail.ch|protonmail.com|pm.me) printf "\033[31mREMEMBER: Protonmail users must install and configure Protonmail Bridge first for the sync to work:\\nhttps://protonmail.com/bridge/\\n\033[0m" && ssltype="None" ;;
|
|
esac
|
|
[ "$sport" = 465 ] && starttlsoff="tls_starttls off"
|
|
fi
|
|
printf "Enter the \033[35mfull name\033[0m you want to be identified by on this account.\\n\tReal name: "
|
|
read -r realname
|
|
printf "Enter a short, \033[36mone-word identifier\033[0m for this email account that will distinguish them from any other accounts you add.\\n\tAccount name: "
|
|
read -r title
|
|
while ! echo "$title" | grep "$namere" >/dev/null || ls "$accdir"/[0-9]"-$title.muttrc" >/dev/null 2>&1; do
|
|
printf "\033[31mTry again\033[0m. Pick a nickname that is one word only including lowercase letters and _ or - and that you have \033[1mnot\033[0m used before.\\n\tAccount name: \033[36m\t"
|
|
read -r title
|
|
printf "\033[0m"
|
|
done
|
|
printf "If your account has a special username different from your address, insert it now. Otherwise leave this prompt totally blank.\\n\033[34mMost accounts will not have a separate login, so you should probably leave this blank.\033[0m\\n\tLogin(?): \033[36m"
|
|
read -r login
|
|
printf "\033[0m"
|
|
[ -z "$login" ] && login="$fulladdr"
|
|
[ "$accounttype" = "offline" ] && printf "If you want to limit the number of messages kept offline to a number, enter that number below. If you do not want to limit your mail and would like \`mbsync\` to sync all mail, press enter without typing a number.\\n\t" && read -r maxmes
|
|
echo "$maxmes" | grep "[1-9]" >/dev/null || maxmes="0"
|
|
getpass
|
|
getprofiles
|
|
mkdir -p "$muttdir" "$accdir" "$cachedir/$title/bodies" "$HOME/.config/msmtp"
|
|
getaccounts
|
|
for x in $(seq 1 9); do echo "$accounts" | grep "$x" >/dev/null 2>&1 || { export idnum="$x"; break ;}; done
|
|
[ ! -f "$msmtprc" ] && echo "$msmtp_header" > "$msmtprc"
|
|
echo "$msmtp_profile" >> "$msmtprc"
|
|
command -V apt-get >/dev/null 2>&1 && ln -s "$msmtprc" "$HOME/.msmtprc" 2>/dev/null
|
|
case "$service" in
|
|
protonmail.ch|protonmail.com|pm.me) protonfinger || return 1 ;;
|
|
esac
|
|
echo "$mutt_profile" > "$accdir/$idnum-$title.muttrc"
|
|
echo "$mbsync_profile" >> "$mbsyncrc"
|
|
notmuchauto
|
|
[ ! -f "$muttrc" ] && echo "# vim: filetype=neomuttrc" > "$muttrc" && echo "muttrc created."
|
|
! grep "^source.*mutt-wizard.muttrc" "$muttrc" >/dev/null && echo "source $mwconfig # mw-autogenerated" >> "$muttrc"
|
|
! grep "^source.*.muttrc" "$muttrc" | grep -v "$mwconfig" >/dev/null && echo "source $accdir/$idnum-$title.muttrc # mw-autogenerated" >> "$muttrc"
|
|
echo "macro index,pager i$idnum '<sync-mailbox><enter-command>source $accdir/$idnum-$title.muttrc<enter><change-folder>!<enter>;<check-stats>' \"switch to $fulladdr\" # mw-autogenerated" >> "$muttrc"
|
|
}
|
|
|
|
protonfinger() { printf "Getting Protonmail bridge fingerprint...\\n"
|
|
fingerprint="$(msmtp --serverinfo --host=127.0.0.1 --port=1025 --tls --tls-certcheck=off | grep SHA256: | sed 's/^.*: //')"
|
|
sed -ibu "s/account $title/&\ntls_trust_file\ntls_fingerprint $fingerprint/" "$msmtprc" ; rm -f "$msmtprc"bu
|
|
}
|
|
|
|
getpass() { while : ; do pass rm -f "mutt-wizard-$title" >/dev/null 2>&1
|
|
pass insert "mutt-wizard-$title" && break; done ;}
|
|
|
|
formatShortcut() { \
|
|
while read -r data; do { echo "macro index,pager g$1 \"<change-folder>$data<enter>\" \"go to $2\" # mw-autogenerated"
|
|
echo "macro index,pager M$1 \";<save-message>$data<enter>\" \"move mail to $2\" # mw-autogenerated"
|
|
echo "macro index,pager C$1 \";<copy-message>$data<enter>\" \"copy mail to $2\" # mw-autogenerated"; } >> "$accdir/$idnum-$title.muttrc"
|
|
done ;}
|
|
|
|
tryconnect() { mkdir -p "$maildir/$title"
|
|
if mailboxes="$(mbsync -l "$title" | sed 's/\//./')" >/dev/null 2>&1 && [ -n "$mailboxes" ]; then
|
|
[ "$accounttype" = "online" ] && sed -ibu "/IMAPStore $title-remote$/,/# End profile/d" "$mbsyncrc" ; rm -f "$mbsyncrc"bu
|
|
printf "\033[32mMailboxes detected.\033[0m\\n"
|
|
echo "$mailboxes" | xargs -I {} mkdir -p "$maildir/$title/{}"
|
|
return 0
|
|
else
|
|
printf "\033[31m\033[31mLog-on not successful.\033[0m\\nIt seems that either you inputted the wrong password or server settings, or there are other requirements for your account out of the control of mutt-wizard.\\n"
|
|
return 1
|
|
fi ;}
|
|
|
|
finalize() { \
|
|
boxes="$(find "$maildir/$title/" -mindepth 1 -type d | sed "s/\ /\\\ /g;s/^.*\//=/;/=\(cur\|new\|tmp\)$/d")"
|
|
[ -z "$boxes" ] && printf "\033[31mNo local mailboxes have been detected for %s.\033[0m\\nThis means that mbsync has not been successfully run.\\nRun mbsync, and if it has an error, be sure to check your password and server settings manually if needbe.\\n" "$title" && return
|
|
printf "Setting default mailboxes for your Inbox, Sent, Drafts and Trash in mutt...\\n"
|
|
spoolfile=$(echo "$boxes" | grep -i -m 1 inbox | sed 's/=/+/g')
|
|
record=$(echo "$boxes" | grep -i -m 1 sent | sed 's/=/+/g')
|
|
postponed=$(echo "$boxes" | grep -i -m 1 draft | sed 's/=/+/g')
|
|
trash=$(echo "$boxes" | grep -i -m 1 trash | sed 's/=/+/g')
|
|
sed -ibu "/^mailboxes\|^set record\|^set postponed\|^set trash\|^set spoolfile/d" "$accdir/$idnum-$title.muttrc" ; rm -f "$accdir/$idnum-$title.muttrcbu"
|
|
{ echo "set spoolfile = \"$spoolfile\""; echo "set record = \"$record\""; echo "set postponed = \"$postponed\""; echo "set trash = \"$trash\""; } >> "$accdir/$idnum-$title.muttrc"
|
|
echo "mailboxes $(echo "$boxes" | sed -e "s/^\|$/\"/g" | tr "\n" " ")" >> "$accdir/$idnum-$title.muttrc"
|
|
printf "Setting up your keyboard shortcuts for jumping between mailboxes...\\n"
|
|
sed -ibu "/# mw-autogenerated/d" "$accdir/$idnum-$title.muttrc" ; rm -f "$accdir/$idnum-$title.muttrcbu"
|
|
echo "$boxes" | grep -i inbox | head -n 1 | formatShortcut i inbox
|
|
echo "$boxes" | grep -i sent | head -n 1 | formatShortcut s sent
|
|
echo "$boxes" | grep -i draft | head -n 1 | formatShortcut d drafts
|
|
echo "$boxes" | grep -i trash | head -n 1 | formatShortcut t trash
|
|
echo "$boxes" | grep -i spam | head -n 1 | formatShortcut S spam
|
|
echo "$boxes" | grep -i junk | head -n 1 | formatShortcut j junk
|
|
echo "$boxes" | grep -i archive | head -n 1 | formatShortcut a archive
|
|
[ "$accounttype" = "offline" ] && printf "All done.\\n\033[33mYou should now be able to run \`\033[32mmbsync %s\033[33m\` to begin to download your mail.\033[0m\\n" "$title"
|
|
command -V urlview >/dev/null 2>&1 && [ ! -f "$HOME/.urlview" ] && echo "COMMAND \$BROWSER" > "$HOME/.urlview"
|
|
return 0
|
|
}
|
|
|
|
confirm() { printf "Do you want to %s? [yes/N]\\n\t" "$@" && read -r input && ! echo "$input" | grep -i "^yes$" >/dev/null && printf "That doesn't seem like a yes to me.\\n\\n" && return 1
|
|
printf "Are you really, really sure you want to %s?\\n\t" "$@" && read -r input && ! echo "$input" | grep -i "^yes$" >/dev/null && printf "That doesn't seem like a yes to me.\\n\\n" && return 1
|
|
return 0 ;}
|
|
|
|
pick() { printf "Select an accounts to %s:\\n" "$1"
|
|
list
|
|
read -r input
|
|
[ -z "$input" ] && return 1
|
|
title="$(echo "$accounts" | grep "$input" | awk '{print $2}')"
|
|
[ -z "$title" ] && printf "Invalid response." && return 1
|
|
return 0 ;}
|
|
|
|
delete() { sed -ibu "/IMAPStore $title-remote$/,/# End profile/d" "$mbsyncrc" ; rm -rf "$mbsyncrc"bu
|
|
rm -rf "${cachedir:?}/${title:?}" "$accdir/"[1-9]"-$title.muttrc"
|
|
sed -ibu "/[0-9]-$title.muttrc/d" "$muttrc" ; rm -f "$muttrc"bu
|
|
sed -ibu "/account $title/,/^\(\s*$\|account\)/d" "$msmtprc"; rm -f "$msmtprc"bu
|
|
}
|
|
|
|
asktype() { while : ; do
|
|
printf "Do you want to keep your mail for this account offline with mbsync? [yes/no]\\n\t"
|
|
read -r offnot
|
|
case "$offnot" in
|
|
[Yy][Ee][Ss]) accounttype="offline" && break ;;
|
|
[Nn][Oo]) accounttype="online" && break ;;
|
|
*) echo "Write out either yes or no completely. Try again or press ctrl-c to quit." ;;
|
|
esac; done ;}
|
|
|
|
purge() { confirm "delete all account data" || exit
|
|
rm -rf "$mbsyncrc" "$accdir" "$HOME/.config/msmtp" "$cachedir"
|
|
echo "All configs and account settings have been purged."
|
|
sed -ibu "/\# mw-autogenerated/d" "$muttrc" ; rm -f "$muttrc"bu
|
|
}
|
|
|
|
syncwrapper() { mbsync -a &
|
|
( kill -46 "$(pidof "${STATUSBAR:-dwmblocks}")" >/dev/null 2>&1 ) 2>/dev/null
|
|
wait
|
|
( kill -46 "$(pidof "${STATUSBAR:-dwmblocks}")" >/dev/null 2>&1 ) 2>/dev/null
|
|
notmuch new
|
|
}
|
|
|
|
notmuchauto() { \
|
|
[ -z "$NOTMUCH_CONFIG" ] && NOTMUCH_CONFIG="$HOME/.notmuch-config"
|
|
[ -f "$NOTMUCH_CONFIG" ] && return 0
|
|
nmbasic="[database]
|
|
path=$maildir
|
|
[user]
|
|
name=$realname
|
|
primary_email=$fulladdr
|
|
[new]
|
|
tags=unread;inbox;
|
|
ignore=.mbsyncstate;.uidvalidity
|
|
[search]
|
|
exclude_tags=deleted;spam;
|
|
[maildir]
|
|
synchronize_flags=true
|
|
[crypto]
|
|
gpg_path=$GPG"
|
|
echo "$nmbasic" > "$NOTMUCH_CONFIG" ;}
|
|
|
|
trap 'echo -e "\033[0m\n"; exit' INT ABRT
|
|
|
|
case "$1" in
|
|
ls) list ;;
|
|
add) asktype && askinfo && tryconnect && finalize || delete ;;
|
|
pass) pick "change the password of" && getpass ;;
|
|
delete) pick delete && confirm "delete the \`$title\` profile" && delete ;;
|
|
sync) syncwrapper ;;
|
|
purge) purge ;;
|
|
*) cat << EOF
|
|
mw: mutt-wizard, auto-configure email accounts for mutt
|
|
including downloadable mail with \`isync\`.
|
|
|
|
Allowed options:
|
|
add Add and autoconfigure an email address (9 max.)
|
|
ls List configured accounts
|
|
delete Pick an account to delete
|
|
purge Delete all accounts and settings
|
|
sync Syncs mail and updates notmuch database
|
|
all else Print this message
|
|
|
|
NOTE: Once at least one account is added, you can run
|
|
\`mbsync -a\` to begin downloading mail.
|
|
EOF
|
|
esac
|