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.
 
 
 
 

434 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. mwaccmuttdir="$mwmuttdir/accounts"
  27. # Location of mail storage
  28. mwmaildir="${MAILDIR:-$HOME/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. mwsharerc="$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. takemwaddr(){
  45. mwacc="$mwaddr" # let the user always just deal with his email
  46. mwaccmutt="${mwaddr//[.@]/_}" # but mutt would not show it with an @ or .
  47. mwacccachedir=$mwcachedir/${mwaddr//[.@]/_} # @ cannot stay because of mutt, . could
  48. mwaccmaildir="$mwmaildir/$mwaccmutt" # folder name as shown by mutt and opens with gf in vim
  49. }
  50. 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/"
  51. do
  52. [ -f "$x" ] && sslcert="$x" && break
  53. done || { echo "CA Certificate not found. Please install one or link it to /etc/ssl/certs/ca-certificates.crt" && exit 1 ;}
  54. getaccounts() {
  55. accounts="$(find "$mwaccmuttdir" -type f | grep -o "[0-9]-.*.muttrc" | sed "s/-/: /;s/\.muttrc//" | sort -n)"
  56. }
  57. mwlist() {
  58. getaccounts && [ -n "$accounts" ] && echo "$accounts"
  59. }
  60. mwadd() {
  61. asktype && askinfo && tryconnect && finalize || mwdelete
  62. }
  63. getprofiles() {
  64. unset msmtp_header msmtp_profile mutt_profile mbsync_profile
  65. printf "Creating profiles for \`%s\`..." "$mwaddr"
  66. msmtp_header="defaults
  67. auth on
  68. tls on
  69. tls_trust_file $sslcert
  70. logfile ${XDG_LOG_HOME:-$HOME}/msmtp.log
  71. "
  72. msmtp_profile="account $mwacc
  73. host $mwsmtp
  74. port $mwsport
  75. from $mwaddr
  76. user $mwlogin
  77. passwordeval \"pass $mwpass\"
  78. $starttlsoff
  79. "
  80. mbsync_profile="IMAPStore $mwacc-remote
  81. Host $mwimap
  82. Port $mwiport
  83. User $mwlogin
  84. PassCmd \"pass $mwpass\"
  85. SSLType $mwssltype
  86. CertificateFile $sslcert
  87. MaildirStore $mwacc-local
  88. Subfolders Verbatim
  89. Path $mwaccmaildir/
  90. Inbox $mwaccmaildir/INBOX
  91. Flatten .
  92. Channel $mwacc
  93. Expunge Both
  94. Master :$mwacc-remote:
  95. Slave :$mwacc-local:
  96. Patterns * !\"[Gmail]/All Mail\"
  97. Create Both
  98. SyncState *
  99. MaxMessages 0
  100. # End profile
  101. "
  102. if [ "$mwtype" = "offline" ]; then
  103. mutt_profile="# vim: filetype=neomuttrc
  104. # muttrc file for account $mwaddr
  105. set realname = \"$mwname\"
  106. set from = \"$mwaddr\"
  107. set sendmail = \"$msmtpbin -a $mwacc\"
  108. alias me $mwname <$mwaddr>
  109. set folder = \"$mwaccmaildir\"
  110. set mbox_type = Maildir
  111. macro index gm \"<shell-escape>mailsync $mwacc<enter>\" \"sync mail $mwaddr\"
  112. unmailboxes *
  113. "
  114. else
  115. mutt_profile="# vim: filetype=neomuttrc
  116. # muttrc file for account $mwaddr
  117. set realname = \"$mwname\"
  118. set from = \"$mwaddr\"
  119. set sendmail = \"$msmtpbin -a $mwacc\"
  120. alias me $mwname <$mwaddr>
  121. set folder = \"imaps://$mwaddr@$mwimap:$mwiport\"
  122. set header_cache = \"$mwacccachedir\"
  123. set message_cachedir = \$header_cache
  124. set imap_user = \"$mwlogin\"
  125. set imap_pass = \"\`pass $mwpass\`\"
  126. account-hook \$folder 'set imap_user=\"$mwlogin\" imap_pass=\"\`pass $mwpass\`\"'
  127. set mbox_type = Maildir
  128. set ssl_starttls = yes
  129. set ssl_force_tls = yes
  130. unmailboxes *
  131. "
  132. fi
  133. printf "DONE.\\n"
  134. }
  135. askinfo() {
  136. if [ -z "$mwaddr" ]; then
  137. printf "Type the \033[31memail address\033[0m\\n\t\033[36m"
  138. read -r mwaddr
  139. printf "\033[0m"
  140. while ! echo "$mwaddr" | grep "$mwemailre" >/dev/null; do
  141. printf "That is not a valid \033[31memail address\033[0m, please retype\\n\t\033[36m"
  142. read -r mwaddr
  143. printf "\033[0m"
  144. done
  145. fi
  146. mwdomain="$(echo "$mwaddr" | sed "s/.*@//")"
  147. printf "\\nSearching for \033[32m%s\033[0m in \033[34m\`domains.csv\`\033[0m..." "$mwdomain"
  148. mwserverinfo="$(grep "^$mwdomain" "$mwshare/domains.csv" 2>/dev/null)"
  149. if [ -z "$mwserverinfo" ]; then
  150. printf "Your email domain is not known to mutt-wizard.\\nType in your settings.\\nUsually you find them by an internet search.\\n"
  151. printf "Type the IMAP server (excluding the port number)\\n\033[36m\t"
  152. read -r mwimap
  153. printf "\033[0mIMAP port number (usually 993)\\n\033[36m\t"
  154. read -r mwiport
  155. printf "\033[0mSMTP server (excluding the port number)\\n\033[36m\t"
  156. read -r mwsmtp
  157. printf "\033[0mSMTP port number (usually 587 or 465)\\n\033[36m\t"
  158. read -r mwsport
  159. 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" "$mwdomain" "$mwimap" "$mwiport" "$mwsmtp" "$mwsport"
  160. else
  161. IFS=, read -r mwservice mwimap mwiport mwsmtp mwsport <<EOF
  162. $mwserverinfo
  163. EOF
  164. 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" "$mwimap" "$mwiport" "$mwsmtp" "$mwsport"
  165. case "$mwservice" in
  166. 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" ;;
  167. 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" ;;
  168. esac
  169. [ "$mwsport" = 465 ] && starttlsoff="tls_starttls off"
  170. fi
  171. if [ -z "$mwname" ]; then
  172. printf "Name to associate to email.\\n\t"
  173. read -r mwname
  174. fi
  175. takemwaddr
  176. if [ -z "$mwlogin" ]; then
  177. 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"
  178. read -r mwlogin
  179. printf "\033[0m"
  180. [ -z "$mwlogin" ] && mwlogin="$mwaddr"
  181. fi
  182. # if the user has a pass entry he could provide it via mwpass
  183. if [ -z "$mwpass" ]; then
  184. mwpass=mutt-wizard-$mwaddr
  185. getpass
  186. fi
  187. getprofiles
  188. mkdir -p "$mwmuttdir" "$mwaccmuttdir" "$mwconfigdir/msmtp" "${mwmbsyncrc%/*}"
  189. if [ ! -f "$mwmsmtprc" ]; then
  190. echo "$msmtp_header" > "$mwmsmtprc"
  191. else
  192. sed -i "/account $mwacc/,/^\(\s*$\|account\)/d" "$mwmsmtprc"
  193. fi
  194. echo "$msmtp_profile" >> "$mwmsmtprc"
  195. case "$mwservice" in
  196. protonmail.ch|protonmail.com|pm.me) protonfinger || return 1 ;;
  197. esac
  198. [ -f "$mwmbsyncrc" ] && sed -i "/IMAPStore $mwacc-remote$/,/# End profile/d" "$mwmbsyncrc"
  199. echo "$mbsync_profile" >> "$mwmbsyncrc"
  200. # new idnum = first one missing
  201. getaccounts
  202. for x in $(seq 1 9); do echo "$accounts" | grep "$x": >/dev/null 2>&1 || { export idnum="$x"; break ;}; done
  203. mwaccmuttrc="$mwaccmuttdir/$idnum-$mwacc.muttrc"
  204. echo "$mutt_profile" > "$mwaccmuttrc"
  205. [ ! -f "$mwmuttrc" ] && echo "# vim: filetype=neomuttrc" > "$mwmuttrc" && echo "muttrc created."
  206. ! grep "source.*mutt-wizard.muttrc" "$mwmuttrc" >/dev/null && echo "source $mwsharerc # mw-autogenerated" >> "$mwmuttrc"
  207. if [ "$mwtype" = "offline" ]; then
  208. ! grep "^macro .* gM .*" "$mwmuttrc" >/dev/null && echo "macro index gM '<shell-escape>mailsync -Va<enter>' \"sync all mail\" # mw-autogenerated" >> "$mwmuttrc"
  209. fi
  210. ! grep "^source.*$mwaccmuttrc" "$mwmuttrc" >/dev/null && echo "source $mwaccmuttrc # mw-autogenerated" >> "$mwmuttrc"
  211. return 0
  212. }
  213. protonfinger() {
  214. printf "Getting Protonmail bridge fingerprint...\\n"
  215. fingerprint="$($msmtpbin --serverinfo --host=127.0.0.1 --port=1025 --tls --tls-certcheck=off)" || return 1
  216. sed -i "s/account $mwacc/&\ntls_trust_file\ntls_fingerprint $fingerprint/" "$mwmsmtprc"
  217. }
  218. getpass() {
  219. while : ; do pass rm -f "$mwpass" >/dev/null 2>&1
  220. pass insert "$mwpass" && break; done ;}
  221. tryconnect() {
  222. if [ ! -d "$mwaccmaildir" ]; then
  223. mwaccmaildirWasThere="NO" # we need to remove again for "online"
  224. mkdir -p "$mwaccmaildir"
  225. fi
  226. if [ -z "$mailboxes" ]; then
  227. mailboxes="$($mbsyncbin -l $mwacc | sed 's/\//./')" >/dev/null 2>&1
  228. fi
  229. if [ -n "$mailboxes" ]; then
  230. spoolfile=$(echo "$mailboxes" | grep -i -m 1 inbox | sed -ne 's/.*/+\0/p')
  231. [ -z "$spoolfile" ] && return 1
  232. #make directories
  233. printf "\033[32mMailboxes detected.\033[0m\\n"
  234. echo "$mailboxes" | xargs -I {} mkdir -p "$mwaccmaildir/{}/"{cur,new,tmp}
  235. record=$(echo "$mailboxes" | grep -i -m 1 sent | sed -ne 's/.*/+\0/p')
  236. [ -z "$record" ] && mkdir -p "$mwaccmaildir/Sent/"{cur,new,tmp} && record="Sent"
  237. postponed=$(echo "$mailboxes" | grep -i -m 1 draft | sed -ne 's/.*/+\0/p')
  238. [ -z "$postponed" ] && mkdir -p "$mwaccmaildir/Drafts/"{cur,new,tmp} && postponed="Drafts"
  239. trash=$(echo "$mailboxes" | grep -i -m 1 trash | sed -ne 's/.*/+\0/p')
  240. [ -z "$trash" ] && mkdir -p "$mwaccmaildir/Trash/"{cur,new,tmp} && trash="Trash"
  241. return 0
  242. else
  243. 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"
  244. return 1
  245. fi
  246. }
  247. finalize() { # new mwaccmuttrc
  248. idnum=${mwaccmuttrc%%-*}
  249. idnum=${idnum##*/}
  250. boxes="$(find "$mwaccmaildir/" -name cur | sed "s,$mwaccmaildir/,,g;s,/cur,,")"
  251. if [[ "$boxes" =~ ^[[:space:]]*$ ]]; then
  252. 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" "$mwacc"
  253. return
  254. fi
  255. mwaccmutt="${email//[.@]/_}"
  256. muttsync=$(printf '<sync-mailbox><enter-command>source %s<enter><change-folder>!<enter>;<check-stats>' $mwaccmuttrc)
  257. cat >> "$mwaccmuttrc" <<EOF
  258. set spoolfile = "$spoolfile"
  259. set record = "$record"
  260. set postponed = "$postponed"
  261. set trash = "$trash"
  262. folder-hook \$folder '$muttsync'
  263. macro index,pager i$idnum '$muttsync' "switch to $email"
  264. mailboxes =$mwaccmutt ===================== $(echo "$boxes" | sed -e "s/ //g;s/.*/\"=\0\"/g" | tr "\n" " ")
  265. EOF
  266. for eqbox in $boxes; do
  267. box=${eqbox##*/}
  268. box=${box##*.}
  269. boxi=${box::2}
  270. boxi=${boxi,,}
  271. cat >> $mwaccmuttrc <<EOF
  272. macro index,pager i$boxi "<change-folder>=$eqbox<enter>" "go to $box"
  273. macro index,pager M$boxi "<save-message>=$eqbox<enter>" "move mail to $box"
  274. macro index,pager C$boxi "<copy-message>=$eqbox<enter>" "copy mail to $box"
  275. EOF
  276. done
  277. if [ "$mwtype" = "offline" ]; then
  278. notmuchauto
  279. printf "All done.\\n\033[33mYou can now run \`\033[32mmailsync [%s]\033[33m\` to sync your mail.\033[0m\\n" "$mwacc"
  280. else
  281. mkdir -p "$mwacccachedir"
  282. sed -i "/IMAPStore $mwacc-remote$/,/# End profile/d" "$mwmbsyncrc"
  283. [ "$mwaccmaildirWasThere" = "NO" ] && rm -rf "$mwaccmaildir/"
  284. fi
  285. return 0
  286. }
  287. confirm() {
  288. 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
  289. return 0 ;
  290. }
  291. mwpick() {
  292. printf "Select an accounts to %s:\\n" "$1"
  293. mwlist
  294. read -r input
  295. [ -z "$input" ] && return 1
  296. mwaddr="$(echo "$accounts" | grep "$input": | awk '{print $2}')"
  297. takemwaddr
  298. [ -z "$mwacc" ] && printf "Invalid response." && return 1
  299. return 0 ;
  300. }
  301. mwdelete() {
  302. sed -i "/IMAPStore $mwacc-remote$/,/# End profile/d" "$mwmbsyncrc"
  303. rm -rf "$mwacccachedir"
  304. rm -rf "$mwaccmuttdir/"[1-9]"-$mwacc.muttrc"
  305. sed -i "/[0-9]-$mwacc.muttrc/d" "$mwmuttrc"
  306. sed -i "/account $mwacc/,/^\(\s*$\|account\)/d" "$mwmsmtprc"
  307. }
  308. mwcron() {
  309. ! pgrep cron >/dev/null && echo "No cron manager running. Install/enable one and then select this option again." && return 1
  310. if crontab -l | grep mailsync >/dev/null; then
  311. echo "Active mail sync cronjob detected. Do you want to remove it?"
  312. printf "\033[36m\t"
  313. read -r rmyn
  314. printf "\033[0m"
  315. echo "$rmyn" | grep -i "^y\(es\)*$" >/dev/null && crontab -l | sed '/mailsync/d' | crontab - >/dev/null && echo "Mail sync turned off."
  316. else
  317. echo "How many minutes between each mail sync?"
  318. printf "\033[36m\t"
  319. read -r minnum
  320. printf "\033[0m"
  321. while ! echo "$minnum" | grep "^[0-9]\+$" >/dev/null; do
  322. printf "That doesn't look like a number. How many minutes between each mail sync?\\n\033[36m\t"
  323. read -r minnum
  324. printf "\033[0m"
  325. done
  326. (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 - &&
  327. echo "Cronjob added. Mail will sync every $minnum minutes. Be sure you have your cron manager running."
  328. fi
  329. }
  330. asktype() {
  331. if [ -z "$mwtype" ]; then
  332. while : ; do
  333. printf "[yes/no]: Local mail via mbsync? No: Mutt remotes (slower)\\n\t"
  334. read -r offnot
  335. case "$offnot" in
  336. [Yy][Ee][Ss]) mwtype="offline" && break ;;
  337. [Nn][Oo]) mwtype="online" && break ;;
  338. *) echo "Write out either yes or no completely. Try again or press ctrl-c to quit." ;;
  339. esac
  340. done
  341. fi
  342. }
  343. mwpurge() {
  344. confirm "delete all account data" || exit
  345. rm -rf "$mwmbsyncrc" "$mwaccmuttdir" "$mwconfigdir/msmtp" "${mwmbsyncrc%/*}" "$mwcachedir"
  346. pgrep cron >/dev/null && crontab -l | sed '/mailsync/d' | crontab - >/dev/null
  347. sed -i "/\# mw-autogenerated/d" "$mwmuttrc"
  348. echo "All configs and account settings have been purged."
  349. }
  350. notmuchauto() {
  351. [ -z "$NOTMUCH_CONFIG" ] && NOTMUCH_CONFIG="$HOME/.notmuch-config"
  352. [ -f "$NOTMUCH_CONFIG" ] && return 0
  353. nmbasic="[database]
  354. path=$mwmaildir
  355. [user]
  356. name=$mwname
  357. primary_email=$mwaddr
  358. [new]
  359. tags=unread;inbox;
  360. ignore=
  361. [search]
  362. exclude_tags=deleted;spam;
  363. [maildir]
  364. synchronize_flags=true
  365. [crypto]
  366. gpg_path=$GPG"
  367. mkdir -p "${NOTMUCH_CONFIG%/*}"
  368. echo "$nmbasic" > "$NOTMUCH_CONFIG"
  369. }
  370. trap 'echo -e "\033[0m\n"; exit' STOP INT ABRT KILL
  371. if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
  372. case "$1" in
  373. ls) mwlist ;;
  374. add) mwadd ;;
  375. pass) mwpick "change the password of" && getpass ;;
  376. delete) mwpick delete && confirm "delete the \`$mwacc\` profile" && mwdelete ;;
  377. purge) mwpurge ;;
  378. cron) mwcron ;;
  379. *) cat << EOF
  380. mw: mutt-wizard, auto-configure email accounts for mutt
  381. including downloadable mail with \`isync\`.
  382. Allowed options:
  383. add Add and autoconfigure an email address (9 max.)
  384. ls List configured accounts
  385. delete Pick an account to delete
  386. purge Delete all accounts and settings
  387. cron Enable or disable an autosync via cronjob
  388. all else Print this message
  389. NOTE: Once at least one account is added, you can run
  390. \`mailsync -a\` to begin downloading mail.
  391. EOF
  392. esac
  393. fi