You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

399 lines
15 KiB

  1. #!/bin/sh
  2. if [ "$#" -gt 1 ]; then
  3. echo "To many arguments. You will be asked."
  4. exit
  5. fi
  6. if [[ -z $prefix ]]; then
  7. case "$(uname)" in
  8. Linux) prefix="/usr" ;;
  9. *) prefix="/usr/local" ;;
  10. esac
  11. fi
  12. command -V gpg >/dev/null 2>&1 && GPG="gpg" || GPG="gpg2"
  13. [ -z $PASSWORD_STORE_DIR ] && PASSWORD_STORE_DIR="$HOME/.password-store"
  14. [ -r "$PASSWORD_STORE_DIR/.gpg-id" ] &&
  15. "$GPG" --list-secret-keys $(cat "$PASSWORD_STORE_DIR/.gpg-id") >/dev/null 2>&1 || {
  16. 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 \`$GPG --full-gen-key\` first.\\n"
  17. exit
  18. }
  19. ! command -v $prefix/bin/mbsync >/dev/null && printf "\`mbsync\` must be installed to run mutt-wizard.\\n" && exit
  20. ! command -v $prefix/bin/msmtp >/dev/null && printf "\`msmtp\` must be installed.\\n" && exit
  21. ! ( command -v mutt >/dev/null || command -v neomutt >/dev/null ) && printf "\`mutt\` must be installed.\\n" && exit
  22. mwconfigdir=${XDG_CONFIG_HOME:-$HOME/.config}
  23. # Main mutt config location
  24. mwmuttdir="$mwconfigdir/mutt"
  25. # Directory for account settings
  26. mwaccdir="$mwmuttdir/accounts"
  27. # Location of mail storage
  28. mwmaildir="${MAILDIR:-${XDG_DATA_HOME:-$HOME/.local/share}/mail}"
  29. # Regex to confirm valid email address
  30. mwemailre=".\+@.\+\\..\+"
  31. mwshare="$prefix/share/mutt-wizard"
  32. if [[ -n $XDG_CONFIG_HOME ]]; then
  33. mwmbsyncrc="$mwconfigdir/isync/mbsyncrc"
  34. else
  35. mwmbsyncrc="$HOME/.mbsyncrc"
  36. fi
  37. mwconfig="$mwshare/mutt-wizard.muttrc"
  38. mwcachedir="${XDG_CACHE_HOME:-$HOME/.cache}/mutt-wizard"
  39. mwmuttrc="$mwmuttdir/muttrc"
  40. mwmsmtprc="$mwconfigdir/msmtp/config"
  41. mwssltype="IMAPS"
  42. mbsyncbin="$prefix/bin/mbsync -c $mwmbsyncrc"
  43. msmtpbin="$prefix/bin/msmtp"
  44. 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/"
  45. do
  46. [ -f "$x" ] && sslcert="$x" && break
  47. done || { echo "CA Certificate not found. Please install one or link it to /etc/ssl/certs/ca-certificates.crt" && exit 1 ;}
  48. getaccounts() {
  49. accounts="$(find "$mwaccdir" -type f | grep -o "[0-9]-.*.muttrc" | sed "s/-/: /;s/\.muttrc//" | sort -n)"
  50. }
  51. mwlist() {
  52. getaccounts && [ -n "$accounts" ] && echo "$accounts"
  53. }
  54. mwadd() {
  55. asktype && askinfo && tryconnect && finalize || mwdelete
  56. }
  57. getprofiles() {
  58. unset msmtp_header msmtp_profile mutt_profile mbsync_profile
  59. printf "Creating profiles for \`%s\`..." "$mwaccount"
  60. msmtp_header="defaults
  61. auth on
  62. tls on
  63. tls_trust_file $sslcert
  64. logfile ${XDG_LOG_HOME:-$HOME}/msmtp.log
  65. "
  66. msmtp_profile="account $mwaccount
  67. host $mwsmtp
  68. port $mwsport
  69. from $mwaddr
  70. user $mwlogin
  71. passwordeval \"pass $mwpass\"
  72. $starttlsoff
  73. "
  74. mbsync_profile="IMAPStore $mwaccount-remote
  75. Host $mwimap
  76. Port $mwiport
  77. User $mwlogin
  78. PassCmd \"pass $mwpass\"
  79. SSLType $mwssltype
  80. CertificateFile $sslcert
  81. MaildirStore $mwaccount-local
  82. Subfolders Verbatim
  83. Path $mwmaildir/$mwaccount/
  84. Inbox $mwmaildir/$mwaccount/INBOX
  85. Flatten .
  86. Channel $mwaccount
  87. Expunge Both
  88. Master :$mwaccount-remote:
  89. Slave :$mwaccount-local:
  90. Patterns * !\"[Gmail]/All Mail\"
  91. Create Both
  92. SyncState *
  93. MaxMessages 0
  94. # End profile
  95. "
  96. if [ "$mwtype" = "offline" ]; then
  97. mutt_profile="# vim: filetype=neomuttrc
  98. # muttrc file for account $mwaccount
  99. set realname = \"$mwname\"
  100. set from = \"$mwaddr\"
  101. set sendmail = \"$msmtpbin -a $mwaccount\"
  102. alias me $mwname <$mwaddr>
  103. set folder = \"$mwmaildir/$mwaccount\"
  104. set mbox_type = Maildir
  105. macro index gm \"<shell-escape>mailsync -V $mwaccount<enter>\" \"sync mail $mwaccount\"
  106. unmailboxes *
  107. "
  108. else
  109. mutt_profile="# vim: filetype=neomuttrc
  110. # muttrc file for account $mwaccount
  111. set realname = \"$mwname\"
  112. set from = \"$mwaddr\"
  113. set sendmail = \"$msmtpbin -a $mwaccount\"
  114. alias me $mwname <$mwaddr>
  115. set folder = \"imaps://$mwaddr@$mwimap:$mwiport\"
  116. set imap_user = \"$mwlogin\"
  117. set header_cache = $mwcachedir/$mwaccount/headers
  118. set message_cachedir = $mwcachedir/$mwaccount/bodies
  119. set imap_pass = \"\`pass $mwpass\`\"
  120. account-hook \$folder 'set imap_user=\$imap_user imap_pass=\$imap_pass'
  121. set mbox_type = Maildir
  122. set ssl_starttls = yes
  123. set ssl_force_tls = yes
  124. unmailboxes *
  125. "
  126. fi
  127. printf "DONE.\\n"
  128. }
  129. askinfo() {
  130. if [ -z $mwaddr ]; then
  131. printf "Type the \033[31memail address\033[0m\\n\t\033[36m"
  132. read -r mwaddr
  133. printf "\033[0m"
  134. while ! echo "$mwaddr" | grep "$mwemailre" >/dev/null; do
  135. printf "That is not a valid \033[31memail address\033[0m, please retype\\n\t\033[36m"
  136. read -r mwaddr
  137. printf "\033[0m"
  138. done
  139. fi
  140. domain="$(echo "$mwaddr" | sed "s/.*@//")"
  141. printf "\\nSearching for \033[32m%s\033[0m in \033[34m\`domains.csv\`\033[0m..." "$domain"
  142. mwserverinfo="$(grep "^$domain" "$mwshare/domains.csv" 2>/dev/null)"
  143. if [ -z "$mwserverinfo" ]; then
  144. printf "Your email domain is not known to mutt-wizard.\\nType in your settings.\\nUsually you find them by an internet search.\\n"
  145. printf "Type the IMAP server (excluding the port number)\\n\033[36m\t"
  146. read -r mwimap
  147. printf "\033[0mIMAP port number (usually 993)\\n\033[36m\t"
  148. read -r mwiport
  149. printf "\033[0mSMTP server (excluding the port number)\\n\033[36m\t"
  150. read -r mwsmtp
  151. printf "\033[0mSMTP port number (usually 587 or 465)\\n\033[36m\t"
  152. read -r mwsport
  153. printf "\033[0m\\nIf you want, you can copy the line below and add it to the \`domains.csv\` file on Github, for others.\\n\\n%s,%s,%s,%s,%s\\n\\nBut be sure the setting works, first! ;-)\\n" "$domain" "$mwimap" "$mwiport" "$mwsmtp" "$mwsport"
  154. else
  155. IFS=, read -r mwservice mwimap mwiport mwsmtp mwsport <<EOF
  156. $mwserverinfo
  157. EOF
  158. printf "\\n\033[3;33mCongrats!\033[0m Server info is known, so you don't need to look it 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\\n" "$imap" "$mwiport" "$mwsmtp" "$mwsport"
  159. case "$mwservice" in
  160. gmail.com) printf "\033[31mGmail: \"less secure\" must be enabled before you continue.\\nDo it now, if you have not done it already:\\nhttps://support.google.com/accounts/answer/6010255\\n\033[0m" ;;
  161. protonmail.ch|protonmail.com|pm.me) printf "\033[31mProtonmail: Users must install and configure Protonmail Bridge for the sync to work:\\nhttps://protonmail.com/bridge/\\n\033[0m" && ssltype="None" ;;
  162. esac
  163. [ "$mwsport" = 465 ] && starttlsoff="tls_starttls off"
  164. fi
  165. if [ -z "$mwname" ]; then
  166. printf "Name to associate to email.\\n\t"
  167. read -r mwname
  168. fi
  169. mwaccount=$mwaddr
  170. if [ -z $mwlogin ]; then
  171. printf "Type your account username if different from your email address.\\n\033[34mFor most accounts you can probably leave this blank.\033[0m\\n\tLogin(?): \033[36m"
  172. read -r mwlogin
  173. printf "\033[0m"
  174. [ -z "$mwlogin" ] && mwlogin="$mwaddr"
  175. fi
  176. if [ -z "$mwpass" ]; then
  177. mwpass=mutt-wizard-$mwaccount
  178. getpass
  179. fi
  180. getprofiles
  181. mkdir -p "$mwmuttdir" "$mwaccdir" "$mwcachedir/$mwaccount/bodies" "$mwconfigdir/msmtp"
  182. getaccounts
  183. for x in $(seq 1 9); do echo "$accounts" | grep "$x": >/dev/null 2>&1 || { export idnum="$x"; break ;}; done
  184. [ ! -f "$mwmsmtprc" ] && echo "$msmtp_header" > "$mwmsmtprc"
  185. echo "$msmtp_profile" >> "$mwmsmtprc"
  186. case "$mwservice" in
  187. protonmail.ch|protonmail.com|pm.me) protonfinger || return 1 ;;
  188. esac
  189. mkdir -p ${mwmbsyncrc%/*}
  190. echo "$mbsync_profile" >> "$mwmbsyncrc"
  191. mwaccrc=$mwaccdir/$idnum-$mwaccount.muttrc
  192. echo "$mutt_profile" > "$mwaccrc"
  193. [ ! -f "$mwmuttrc" ] && echo "# vim: filetype=neomuttrc" > "$mwmuttrc" && echo "muttrc created."
  194. ! grep "source.*mutt-wizard.muttrc" "$mwmuttrc" >/dev/null && echo "source $mwconfig # mw-autogenerated" >> "$mwmuttrc"
  195. if [ "$mwtype" = "offline" ]; then
  196. ! grep "^macro .* gM .*" "$mwmuttrc" >/dev/null && echo "macro index gM '<shell-escape>mailsync -Va<enter>' \"sync all mail\" # mw-autogenerated" >> "$mwmuttrc"
  197. fi
  198. muttsync="<sync-mailbox><enter-command>source $mwaccrc<enter><change-folder>\!<enter>;<check-stats>"
  199. ! grep "^source.*$idnum-$mwaccount.muttrc" "$mwmuttrc" >/dev/null && echo "source $mwaccrc # mw-autogenerated" >> "$mwmuttrc"
  200. ! grep "^folder-hook.*$idnum-$mwaccount.muttrc" "$mwmuttrc" >/dev/null && echo "folder-hook \$folder '$muttsync' # mw-autogenerated" >> "$mwmuttrc"
  201. ! grep "^macro .* i$idnum .*" "$mwmuttrc" >/dev/null && echo "macro index,pager i$idnum '$muttsync' \"switch to $mwaddr\" # mw-autogenerated" >> "$mwmuttrc"
  202. return 0
  203. }
  204. protonfinger() {
  205. printf "Getting Protonmail bridge fingerprint...\\n"
  206. fingerprint="$($msmtpbin --serverinfo --host=127.0.0.1 --port=1025 --tls --tls-certcheck=off)" || return 1
  207. sed -i "s/account $mwaccount/&\ntls_trust_file\ntls_fingerprint $fingerprint/" "$mwmsmtprc"
  208. }
  209. getpass() {
  210. while : ; do pass rm -f "$mwpass" >/dev/null 2>&1
  211. pass insert "$mwpass" && break; done ;}
  212. formatShortcut() {
  213. while read -r data; do { echo "macro index,pager g$1 \"<change-folder>$data<enter>\" \"go to $2\" # mw-autogenerated"
  214. echo "macro index,pager M$1 \"<save-message>$data<enter>\" \"move mail to $2\" # mw-autogenerated"
  215. echo "macro index,pager C$1 \"<copy-message>$data<enter>\" \"copy mail to $2\" # mw-autogenerated"; } >> "$mwaccrc"
  216. done
  217. }
  218. tryconnect() {
  219. if [ -z "$mailboxes" ]; then
  220. mkdir -p $mwmaildir/$mwaccount
  221. mailboxes="$($mbsyncbin -l $mwaccount | sed 's/\//./')" >/dev/null 2>&1
  222. fi
  223. if [ -n "$mailboxes" ]; then
  224. [ "$mwtype" = "online" ] && sed -i "/IMAPStore $mwaccount-remote$/,/# End profile/d" "$mwmbsyncrc"
  225. [ "$mwtype" = "offline" ] && notmuchauto
  226. printf "\033[32mMailboxes detected.\033[0m\\n"
  227. echo "$mailboxes" | xargs -I {} mkdir -p "$mwmaildir/$mwaccount/{}"
  228. return 0
  229. else
  230. 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"
  231. return 1
  232. fi
  233. }
  234. finalize() {
  235. boxes="$(find "$mwmaildir/$mwaccount/" -mindepth 1 -maxdepth 1 | sed "s/\ /\\\ /g;s/^.*\//=/")"
  236. [ -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" "$mwaccount" && return
  237. printf "Setting default mailboxes for your Inbox, Sent, Drafts and Trash in mutt...\\n"
  238. spoolfile=$(echo "$boxes" | grep -i -m 1 inbox | sed 's/=/+/g')
  239. record=$(echo "$boxes" | grep -i -m 1 sent | sed 's/=/+/g')
  240. postponed=$(echo "$boxes" | grep -i -m 1 draft | sed 's/=/+/g')
  241. trash=$(echo "$boxes" | grep -i -m 1 trash | sed 's/=/+/g')
  242. sed -i "/^mailboxes\|^set record\|^set postponed\|^set trash\|^set spoolfile/d" "$mwaccrc"
  243. { echo "set spoolfile = \"$spoolfile\""; echo "set record = \"$record\""; echo "set postponed = \"$postponed\""; echo "set trash = \"$trash\""; } >> "$mwaccrc"
  244. mwaccount_="${mwaccount//[.@]/_}"
  245. echo "mailboxes =${mwaccount_%_*} ===================== $(echo "$boxes" | sed -e "s/^\|$/\"/g" | tr "\n" " ")" >> "$mwaccrc"
  246. printf "Setting up your keyboard shortcuts for jumping between mailboxes...\\n"
  247. sed -i "/# mw-autogenerated/d" "$mwaccrc"
  248. echo "$boxes" | grep -i inbox | head -n 1 | formatShortcut i inbox
  249. echo "$boxes" | grep -i sent | head -n 1 | formatShortcut s sent
  250. echo "$boxes" | grep -i draft | head -n 1 | formatShortcut d drafts
  251. echo "$boxes" | grep -i trash | head -n 1 | formatShortcut t trash
  252. echo "$boxes" | grep -i spam | head -n 1 | formatShortcut S spam
  253. echo "$boxes" | grep -i junk | head -n 1 | formatShortcut j junk
  254. echo "$boxes" | grep -i archive | head -n 1 | formatShortcut a archive
  255. [ "$mwtype" = "offline" ] && printf "All done.\\n\033[33mYou can now run \`\033[32mmailsync [%s]\033[33m\` to sync your mail.\033[0m\\n" "$mwaccount"
  256. command -V urlview >/dev/null 2>&1 && [ ! -f "$HOME/.urlview" ] && echo "COMMAND \$BROWSER" > "$HOME/.urlview"
  257. return 0
  258. }
  259. confirm() {
  260. printf "[y/N]: Do you want to %s?\\n\t" "$@" && read -r input && ! echo "$input" | grep -i "^y$\|^yes$" >/dev/null && printf "That doesn't seem like a yes to me.\\n\\n" && return 1
  261. return 0 ;
  262. }
  263. mwpick() {
  264. printf "Select an accounts to %s:\\n" "$1"
  265. mwlist
  266. read -r input
  267. [ -z "$input" ] && return 1
  268. mwaddr="$(echo "$accounts" | grep "$input": | awk '{print $2}')"
  269. mwaccount=$mwaddr
  270. [ -z "$mwaccount" ] && printf "Invalid response." && return 1
  271. return 0 ;
  272. }
  273. mwdelete() {
  274. sed -i "/IMAPStore $mwaccount-remote$/,/# End profile/d" "$mwmbsyncrc"
  275. rm -rf "${mwcachedir:?}/${mwaccount:?}"
  276. rm -rf "$mwaccdir/"[1-9]"-$mwaccount.muttrc"
  277. sed -i "/[0-9]-$mwaccount.muttrc/d" "$mwmuttrc"
  278. sed -i "/account $mwaccount/,/^\(\s*$\|account\)/d" "$mwmsmtprc"
  279. }
  280. mwcron() {
  281. ! pgrep cron >/dev/null && echo "No cron manager running. Install/enable one and then select this option again." && return 1
  282. if crontab -l | grep mailsync >/dev/null; then
  283. echo "Active mail sync cronjob detected. Do you want to remove it?"
  284. printf "\033[36m\t"
  285. read -r rmyn
  286. printf "\033[0m"
  287. echo "$rmyn" | grep -i "^y\(es\)*$" >/dev/null && crontab -l | sed '/mailsync/d' | crontab - >/dev/null && echo "Mail sync turned off."
  288. else
  289. echo "How many minutes between each mail sync?"
  290. printf "\033[36m\t"
  291. read -r minnum
  292. printf "\033[0m"
  293. while ! echo "$minnum" | grep "^[0-9]\+$" >/dev/null; do
  294. printf "That doesn't look like a number. How many minutes between each mail sync?\\n\033[36m\t"
  295. read -r minnum
  296. printf "\033[0m"
  297. done
  298. (crontab -l; echo "*/$minnum * * * * export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u)/bus; export DISPLAY=:0; $(type mailsync | cut -d' ' -f3)") | crontab - &&
  299. echo "Cronjob added. Mail will sync every $minnum minutes. Be sure you have your cron manager running."
  300. fi
  301. }
  302. asktype() {
  303. if [ -z "$mwtype" ]; then
  304. while : ; do
  305. printf "[yes/no]: Local mail via mbsync? No: Mutt remotes (slower)\\n\t"
  306. read -r offnot
  307. case "$offnot" in
  308. [Yy][Ee][Ss]) mwtype="offline" && break ;;
  309. [Nn][Oo]) mwtype="online" && break ;;
  310. *) echo "Write out either yes or no completely. Try again or press ctrl-c to quit." ;;
  311. esac
  312. done
  313. fi
  314. }
  315. mwpurge() {
  316. confirm "delete all account data" || exit
  317. rm -rf "$mwmbsyncrc" "$mwaccdir" "$mwconfigdir/msmtp" "$mwcachedir"
  318. pgrep cron >/dev/null && crontab -l | sed '/mailsync/d' | crontab - >/dev/null
  319. sed -i "/\# mw-autogenerated/d" "$mwmuttrc"
  320. echo "All configs and account settings have been purged."
  321. }
  322. notmuchauto() {
  323. [ -z "$NOTMUCH_CONFIG" ] && NOTMUCH_CONFIG="$HOME/.notmuch-config"
  324. [ -f "$NOTMUCH_CONFIG" ] && return 0
  325. nmbasic="[database]
  326. path=$mwmaildir
  327. [user]
  328. name=$mwname
  329. primary_email=$mwaddr
  330. [new]
  331. tags=unread;inbox;
  332. ignore=
  333. [search]
  334. exclude_tags=deleted;spam;
  335. [maildir]
  336. synchronize_flags=true
  337. [crypto]
  338. gpg_path=$GPG"
  339. mkdir -p ${NOTMUCH_CONFIG%/*}
  340. echo "$nmbasic" > "$NOTMUCH_CONFIG"
  341. }
  342. trap 'echo -e "\033[0m\n"; exit' STOP INT ABRT KILL
  343. if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
  344. case "$1" in
  345. ls) mwlist ;;
  346. add) mwadd ;;
  347. pass) mwpick "change the password of" && getpass ;;
  348. delete) mwpick delete && confirm "delete the \`$mwaccount\` profile" && mwdelete ;;
  349. purge) mwpurge ;;
  350. cron) mwcron ;;
  351. *) cat << EOF
  352. mw: mutt-wizard, auto-configure email accounts for mutt
  353. including downloadable mail with \`isync\`.
  354. Allowed options:
  355. add Add and autoconfigure an email address (9 max.)
  356. ls List configured accounts
  357. delete Pick an account to delete
  358. purge Delete all accounts and settings
  359. cron Enable or disable an autosync via cronjob
  360. all else Print this message
  361. NOTE: Once at least one account is added, you can run
  362. \`mailsync -a\` to begin downloading mail.
  363. EOF
  364. esac
  365. fi