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.
 
 
 
 

759 lines
25 KiB

  1. #!/bin/sh
  2. VERSION="2.0"
  3. if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
  4. prefix=${0}
  5. else
  6. prefix="$BASH_SOURCE"
  7. fi
  8. [ ! ${prefix::1} = "/" ] && prefix="$PWD/$prefix"
  9. prefix="${prefix%/bin/*}"
  10. mwbin="$prefix/bin/mw"
  11. _MW_="mutt-wizard"
  12. _MW_generated="mutt-wizard-generated"
  13. mwconfigdir=${XDG_CONFIG_HOME:-$HOME/.config}
  14. # Main mutt config location
  15. mwmuttdir="$mwconfigdir/mutt"
  16. mwmuttrc="$mwmuttdir/muttrc"
  17. # Directory for account settings
  18. mwaccmuttdir="$mwmuttdir/accounts"
  19. # Generated at every full sync
  20. mwgenmuttaccs=$mwmuttdir/mw_gen_mutt_accounts.muttrc
  21. # Location of mail storage
  22. mwmaildir="${MAILDIR:-$HOME/mail}"
  23. # Regex to confirm valid email address
  24. mwemailre=".\+@.\+\\..\+"
  25. mwshare="$prefix/share/$_MW_"
  26. mwmbsyncrc="$mwconfigdir/isync/mbsyncrc"
  27. mwgetmaildir=$mwconfigdir/getmail # POP3
  28. mwmsmtprc="$mwconfigdir/msmtp/config"
  29. mwsharerc="$mwshare/$_MW_.muttrc"
  30. mwcachedir="${XDG_CACHE_HOME:-$HOME/.cache}/$_MW_"
  31. _mwtakeaddr(){
  32. mwaccmaildir="$mwmaildir/$mwaddr" # mail dir is $MAILDIR/email
  33. mwacccachedir=$mwcachedir/${mwaddr//[.@]/_} # @ cannot stay because of mutt, . could
  34. [ -n "$mwpass" ] || mwpass=$_MW_-$mwaddr
  35. [ -n "$mwidnum" ] && mwaccmuttrc="$mwaccmuttdir/$mwidnum-$mwaddr.mwonofftype.$mwtype.muttrc"
  36. }
  37. _mwaddrs() {
  38. mwaddrs="$(find "$mwaccmuttdir" -type f | grep -o "[1-9]-.*.muttrc" | sed "s/-/: /;s/\.muttrc//" | sort -n)"
  39. }
  40. _mwgetpass() {
  41. while : ; do pass rm -f "$mwpass" >/dev/null 2>&1
  42. pass insert "$mwpass" && break; done ;
  43. }
  44. _mwcheckcert() {
  45. for mwcrt in "/etc/ssl/certs/ca-certificates.crt" "/etc/pki/tls/certs/ca-bundle.crt" "/etc/ssl/ca-bundle.pem" \
  46. "/etc/pki/tls/cacert.pem" "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" "/etc/ssl/cert.pem" "/usr/local/share/ca-certificates/"
  47. do
  48. [ -f "$mwcrt" ] && mwsslcert="$mwcrt" && break
  49. done || { echo "CA Certificate not found. Please install one or link it to /etc/ssl/certs/ca-certificates.crt" && return 1 ;}
  50. }
  51. _mwcheckinternet() {
  52. # Checks for internet connection
  53. if type systemctl >/dev/null; then
  54. if ! systemctl --type service | grep net | grep active > /dev/null; then
  55. echo "No internet connection."
  56. return 1
  57. fi
  58. else
  59. if ! ping -q -c 1 1.1.1.1 > /dev/null; then
  60. echo "No internet connection (ping failed)."
  61. return 1
  62. fi
  63. fi
  64. }
  65. _mwasktype() {
  66. if [ -z "$mwtype" ]; then
  67. while : ; do
  68. printf "Do you want to sync your mails using the command 'mw' outside mutt? [yes/no]\\n"
  69. printf "'no' makes Neomutt slow for IMAP accounts, so probably you want 'yes'.\\n\t"
  70. read -r mwoffline
  71. case "$mwoffline" in
  72. [Yy][Ee][Ss]) mwtype="offline" && break ;;
  73. [Nn][Oo]) mwtype="online" && break ;;
  74. *) echo "Write out either yes or no completely. Try again or press ctrl-c to quit." ;;
  75. esac
  76. done
  77. fi
  78. if [ "$mwtype" == "offline" ]; then
  79. ! type "msmtp" >/dev/null && printf "\033[31m\`msmtp\` must be installed. You can do that afterwards.\\n\033[0m"
  80. else
  81. ! ( type mutt >/dev/null || type neomutt >/dev/null ) && printf "\033[31m\`mutt\` must be installed. You can do that afterwards.\\n\033[0m"
  82. fi
  83. return 0
  84. }
  85. _mwaskinfo() {
  86. if [ -z "$mwaddr" ]; then
  87. printf "Type the \033[31memail address\033[0m\\n\t\033[36m"
  88. read -r mwaddr
  89. printf "\033[0m"
  90. while ! echo "$mwaddr" | grep "$mwemailre" >/dev/null; do
  91. printf "That is not a valid \033[31memail address\033[0m, please retype\\n\t\033[36m"
  92. read -r mwaddr
  93. printf "\033[0m"
  94. done
  95. fi
  96. mwdomain="$(echo "$mwaddr" | sed "s/.*@//")"
  97. if [ -z "$mwserverinfo" ]; then
  98. printf "\\nSearching for \033[32m%s\033[0m in \033[34m\`domains.csv\`\033[0m..." "$mwdomain"
  99. mwserverinfo="$(grep "^$mwdomain" "$mwshare/domains.csv" 2>/dev/null)"
  100. fi
  101. if [ -z "$mwserverinfo" ]; then
  102. printf "Your email domain is not known to $_MW_.\\nType in your settings.\\n"
  103. printf "Usually you find them by an internet search.\\n"
  104. printf "Type the IMAP/POP3 server (excluding the port number)\\n\033[36m\t"
  105. read -r mwurl
  106. printf "\033[0mIMAP port number (usually 993)\\n\033[36m\t"
  107. read -r mwport
  108. printf "\033[0mSMTP server (excluding the port number)\\n\033[36m\t"
  109. read -r mwsurl
  110. printf "\033[0mSMTP port number (usually 587 or 465)\\n\033[36m\t"
  111. read -r mwsport
  112. 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"
  113. printf "%s,%s,%s,%s,%s\\n\\nBut be sure the setting works, first! ;-)\\n" "$mwdomain" "$mwurl" "$mwport" "$mwsurl" "$mwsport"
  114. else # found server info
  115. IFS=, read -r mwservice mwurl mwport mwsurl mwsport <<EOF
  116. $mwserverinfo
  117. EOF
  118. printf "\\n\033[3;33mCongrats!\033[0m Server info is known, so you don't need to look it up!\\n"
  119. printf "\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" \
  120. "$mwurl" "$mwport" "$mwsurl" "$mwsport"
  121. case "$mwservice" in
  122. 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" ;;
  123. 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" && mwssltype="None" ;;
  124. esac
  125. fi
  126. if [ -z "$mwname" ]; then
  127. printf "Name to associate to email.\\n\t"
  128. read -r mwname
  129. fi
  130. if [ -z "$mwlogin" ]; then
  131. printf "Type your account username if different from your email address.\\n"
  132. printf "\033[34mFor most accounts you can probably leave this blank.\033[0m\\n\tLogin(?): \033[36m"
  133. read -r mwlogin
  134. printf "\033[0m"
  135. [ -z "$mwlogin" ] && mwlogin="$mwaddr"
  136. fi
  137. # if the user has a pass entry he could provide it via mwpass
  138. if [ -z "$mwpass" ]; then
  139. mwpass=$_MW_-$mwaddr
  140. _mwgetpass
  141. fi
  142. _mwtakeaddr
  143. if [ "$mwport" = "110" ] || [ "$mwport" = "995" ]; then # POP3
  144. [ "$mwport" = "110" ] && mwkind="pop" || mwkind="pops"
  145. else
  146. [ "$mwport" = "143" ] && mwkind="imap" || mwkind="imaps"
  147. [ "$mwkind" = "imap" ] && mwssltype="None" || mwssltype=${mwssltype:-${mwkind^^}}
  148. fi
  149. [ "$mwsport" = "465" ] && mwstarttlsoff="tls_starttls off"
  150. return 0
  151. }
  152. _mwsmtp() {
  153. mkdir -p "${mwmsmtprc%/*}"
  154. if [ ! -f "$mwmsmtprc" ]; then
  155. cat > "$mwmsmtprc" <<EOF
  156. defaults
  157. auth on
  158. tls on
  159. tls_trust_file $mwsslcert
  160. #logfile ${XDG_LOG_HOME:-$HOME}/msmtp.log
  161. EOF
  162. else
  163. sed -i "/account $mwaddr/,/^\(\s*$\|account\)/d" "$mwmsmtprc" &>/dev/null
  164. fi
  165. cat >> "$mwmsmtprc" <<EOF
  166. account $mwaddr
  167. host $mwsurl
  168. port $mwsport
  169. from $mwaddr
  170. user $mwlogin
  171. passwordeval "pass $mwpass"
  172. $mwstarttlsoff
  173. EOF
  174. case "$mwservice" in
  175. protonmail.ch|protonmail.com|pm.me) _mwprotonfinger || return 1 ;;
  176. esac
  177. }
  178. _mwprotonfinger() {
  179. printf "Getting Protonmail bridge fingerprint...\\n"
  180. mwfingerprint="$(msmtp --serverinfo --host=127.0.0.1 --port=1025 --tls --tls-certcheck=off)" || return 1
  181. sed -i "s/account $mwaddr/&\ntls_trust_file\ntls_fingerprint $mwfingerprint/" "$mwmsmtprc" &>/dev/null
  182. }
  183. _mwmbsync() {
  184. mkdir -p "${mwmbsyncrc%/*}"
  185. [ -f "$mwmbsyncrc" ] && sed -i "/IMAPStore $mwaddr-remote$/,/# End $_MW_ profile/d" "$mwmbsyncrc"
  186. cat >> "$mwmbsyncrc" <<EOF
  187. IMAPStore $mwaddr-remote
  188. Host $mwurl
  189. Port $mwport
  190. User $mwlogin
  191. PassCmd "pass $mwpass"
  192. SSLType $mwssltype
  193. CertificateFile $mwsslcert
  194. MaildirStore $mwaddr-local
  195. Subfolders Verbatim
  196. Path $mwaccmaildir/
  197. Inbox $mwaccmaildir/INBOX
  198. Channel $mwaddr
  199. Expunge Both
  200. Master :$mwaddr-remote:
  201. Slave :$mwaddr-local:
  202. Patterns * !"_/*" !"[Gmail]" !"[Gmail]/All Mail"
  203. Create Both
  204. SyncState *
  205. MaxMessages 0
  206. # End $_MW_ profile
  207. EOF
  208. }
  209. _mwpop() {
  210. mkdir -p "$mwgetmaildir"
  211. cat > "$mwgetmaildir/$mwaddr" <<EOF
  212. [retriever]
  213. type = SimplePOP3SSLRetriever
  214. server = $mwurl
  215. username = $mwlogin
  216. port = $mwport
  217. password_command = ("pass", "$mwpass")
  218. [destination]
  219. type = Maildir
  220. path = $mwaccmaildir/INBOX/
  221. [options]
  222. read_all = true
  223. delete = true
  224. #message_log = ${XDG_LOG_HOME:-$HOME}/getmail.log
  225. # vim: ft=conf
  226. EOF
  227. }
  228. _mwprofiles() {
  229. printf "Creating profiles for \`%s\`..." "$mwaddr"
  230. # mutt
  231. [ ! -f "$mwgenmuttaccs" ] && _mwgenmuttaccs
  232. if [ "$mwtype" = "offline" ]; then # not online, actually outside mutt
  233. if [ "${mwkind::3}" = "pop" ]; then
  234. ! type getmail >/dev/null && printf "\033[31mFor POP3 \`getmail\` must be installed to use \`mw\`. You can do that afterwards.\\n\033[0m"
  235. _mwpop
  236. else
  237. ! type mbsync >/dev/null && printf "\033[31mFor IMAP \`mbsync\` must be installed to use \`mw\`. You can do that afterwards.\\n\033[0m"
  238. _mwmbsync
  239. fi
  240. _mwsmtp
  241. fi
  242. return 0
  243. }
  244. _mwtryconnect() {
  245. if [ ! -d "$mwaccmaildir" ]; then
  246. [ ! "${mwkind::3}" = "pop" ] && mwaccmaildirWasThere="NO" # mutt uses $mwacccachedir for "online" IMAP, so clean up later
  247. mkdir -p "$mwaccmaildir"
  248. fi
  249. if [ -z "$mwmailboxes" ]; then
  250. #just check server, no mail retrieval
  251. if [ "${mwkind::3}" = "pop" ]; then
  252. [ "$mwport" = "110" ] && mwp="POP3" || mwp="POP3_SSL"
  253. python -c "from poplib import $mwp;p=$mwp('$mwurl');print(p.getwelcome());p.quit()" | \
  254. grep "+OK" && mwmailboxes="INBOX"
  255. else
  256. # for online do without mbsync, i.e. don't require it for mail setup, either
  257. [ "$mwport" = "143" ] && mwi="IMAP4" || mwi="IMAP4_SSL"
  258. mwpw="$(pass $mwpass)"
  259. mwmailboxes="$(python -c "from imaplib import $mwi;m=$mwi('$mwurl');m.login('$mwlogin','$mwpw');b=m.list()[1];print('\n'.join(e.split(b' \"/\" ')[-1].strip(b'\"').decode() for e in b if all(x not in e for x in [b'[Gmail]/All Mail',b'Noselect',b'HasChildren'])));m.logout()")"
  260. fi
  261. fi
  262. if [ -n "$mwmailboxes" ]; then
  263. mwspoolfile=$(echo "$mwmailboxes" | grep -i -m 1 inbox | sed -ne 's/.*/+\0/p')
  264. [ -z "$mwspoolfile" ] && printf "\033[31mNo spoolfile.\033[0m\\n" && return 1
  265. printf "\033[32mMailboxes detected.\033[0m\\n"
  266. if [ -z "$mwserverinfo" ]; then
  267. printf "\033[32mPlease add the line below at https://github.com/rpuntaie/mutt-wizard/issues/1\033[0m\\n\\n"
  268. printf "\033[31m$mwservice,$mwurl,$mwport,$mwsurl,$mwsport\0330m\\n\\n"
  269. fi
  270. echo "$mwmailboxes" | xargs -I {} mkdir -p "$mwaccmaildir/{}/"{cur,new,tmp}
  271. return 0
  272. else
  273. printf "\033[31mLog-on not successful.\033[0m\\n"
  274. printf "It seems that either you entered the wrong password or server settings, or there are other requirements for your account out of the control of $_MW_.\\n"
  275. return 1
  276. fi
  277. }
  278. _mwnotmuchauto() {
  279. [ -z "$NOTMUCH_CONFIG" ] && NOTMUCH_CONFIG="$HOME/.notmuch-config"
  280. [ -f "$NOTMUCH_CONFIG" ] && return 0
  281. mkdir -p "${NOTMUCH_CONFIG%/*}"
  282. cat > "$NOTMUCH_CONFIG" <<EOF
  283. [database]
  284. path=$mwmaildir
  285. [user]
  286. name=$mwname
  287. primary_email=$mwaddr
  288. [new]
  289. tags=new
  290. ignore=
  291. [search]
  292. exclude_tags=deleted;spam;
  293. [maildir]
  294. synchronize_flags=true
  295. [crypto]
  296. gpg_path=$GPG"
  297. EOF
  298. }
  299. _mwfinalize() { # new mwaccmuttrc
  300. if [ "$mwtype" = "online" ]; then
  301. if [ ! "${mwkind::3}" = "pop" ]; then
  302. mkdir -p "$mwacccachedir"
  303. fi
  304. fi
  305. _mwgenmwaccmuttrc || return 1
  306. if [ "$mwtype" = "offline" ]; then # not online
  307. _mwnotmuchauto
  308. printf "All done.\\n\033[33mYou can now run \`\033[32mmw [%s]\033[33m\` to sync your mail.\033[0m\\n" "$mwaddr"
  309. elif [ "${mwkind::3}" = "pop" ]; then # and online
  310. _mwnotmuchauto #still usable for online (in mutt) pop
  311. fi
  312. if [ "$mwtype" = "online" ]; then
  313. [ "$mwaccmaildirWasThere" = "NO" ] && rm -rf "$mwaccmaildir" &>/dev/null
  314. fi
  315. return 0
  316. }
  317. _mwdelete() {
  318. [ "$mwaccmaildirWasThere" = "NO" ] && rm -rf "$mwaccmaildir" &>/dev/null
  319. rm -f "$mwaccmuttrc" &>/dev/null
  320. if [ "$mwtype" = "offline" ]; then # not online
  321. sed -i "/${mwaccmuttrc//\//\\\/}/d" "$mwgenmuttaccs" &>/dev/null
  322. sed -i "/account $mwaddr/,/^\(\s*$\|account\)/d" "$mwmsmtprc" &>/dev/null
  323. if [ -f "$mwgetmaildir/$mwaddr" ]; then
  324. rm -f "$mwgetmaildir/$mwaddr" &>/dev/null
  325. else
  326. sed -i "/IMAPStore $mwaddr-remote$/,/# End $_MW_ profile/d" "$mwmbsyncrc" &>/dev/null
  327. fi
  328. else
  329. sed -i "/${mwaccmuttrc//\//\\\/}/d" "$mwmuttrc" &>/dev/null
  330. rm -rf "$mwacccachedir" &>/dev/null
  331. fi
  332. }
  333. _mwadd() {
  334. type gpg >/dev/null 2>&1 && GPG="gpg" || GPG="gpg2"
  335. [ -z "$PASSWORD_STORE_DIR" ] && PASSWORD_STORE_DIR="$HOME/.password-store"
  336. [ -r "$PASSWORD_STORE_DIR/.gpg-id" ] &&
  337. "$GPG" --list-secret-keys $(cat "$PASSWORD_STORE_DIR/.gpg-id") >/dev/null 2>&1 || {
  338. printf "\`pass\` must be installed and initialized to encrypt passwords.\\nBe sure it is installed and run \`pass init <yourgpgemail>\`.\\n"
  339. printf "If you don't have a GPG public private key pair, run \`$GPG --full-gen-key\` first.\\n"
  340. return 1
  341. }
  342. _mwcheckcert && _mwcheckinternet && _mwasktype && _mwaskinfo && _mwprofiles && _mwtryconnect && _mwfinalize || _mwdelete
  343. }
  344. _mwconfirm() {
  345. printf "[y/N]: Do you want to %s?\\n\t" "$@" && read -r mwinput && ! echo "$mwinput" | grep -i "^y$\|^yes$" >/dev/null \
  346. && printf "That doesn't seem like a yes to me.\\n\\n" && return 1
  347. return 0 ;
  348. }
  349. _mwlist() {
  350. _mwaddrs && [ -n "$mwaddrs" ] && echo "${mwaddrs//.mwonofftype./ }"
  351. }
  352. _mwpick() {
  353. printf "Select an accounts to %s:\\n" "$1"
  354. _mwlist
  355. [ -z "$mwpick" ] && read -r mwpick
  356. mwidnum="$mwpick"
  357. [ -z "$mwidnum" ] && return 1
  358. mwaddr="$(echo "$mwaddrs" | grep -i -m 1 "$mwidnum:" | sed "s/\.mwonofftype\./ /" | awk '{print $2}')"
  359. mwtype="$(echo "$mwaddrs" | grep -i -m 1 "$mwidnum:" | sed "s/\.mwonofftype\./ /" | awk '{print $3}')"
  360. _mwtakeaddr
  361. [ -z "$mwaddr" ] && printf "Invalid response." && return 1
  362. return 0 ;
  363. }
  364. _mwcron() {
  365. ! pgrep cron >/dev/null && echo "No cron manager running. Install/enable one and then select this option again." && return 1
  366. if crontab -l | grep "mw sync" >/dev/null; then
  367. if [ -z $mwcronminutes ]; then
  368. echo "Active mail sync cronjob detected. Do you want to remove it?"
  369. printf "\033[36m\t"
  370. [ -z $mwcronremove ] && read -r mwcronremove
  371. printf "\033[0m"
  372. else # remove to add again
  373. mwcronremove="yes"
  374. fi
  375. echo "$mwcronremove" | grep -i "^y\(es\)*$" >/dev/null && crontab -l | sed '/mw sync/d' | crontab - >/dev/null \
  376. && echo "mw cronjob removed."
  377. [ -z $mwcronminutes ] && return
  378. fi
  379. if [ -z $mwcronminutes ]; then
  380. echo "How many minutes between each mail sync?"
  381. printf "\033[36m\t"
  382. [ -z $mwcronminutes ] && read -r mwcronminutes
  383. printf "\033[0m"
  384. fi
  385. while ! echo "$mwcronminutes" | grep "^[1-9]\+$" >/dev/null; do
  386. printf "That doesn't look like a number. How many minutes between each mail sync?\\n\033[36m\t"
  387. read -r mwcronminutes
  388. printf "\033[0m"
  389. done
  390. (crontab -l; echo "*/$mwcronminutes * * * * export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u)/bus; export DISPLAY=:0; $mwbin sync") \
  391. | crontab - && echo "mw cronjob added. Mail will sync every $mwcronminutes minutes. Be sure you have your cron manager running."
  392. }
  393. _mwpurge() {
  394. _mwconfirm "Remove all $_MW_ data" || exit
  395. mwaddrs="$(find "$mwaccmuttdir" -type f | grep -o "[1-9]-.*.muttrc" | sed "s/\.muttrc//")"
  396. for mwaddrsentry in $mwaddrs; do
  397. mwtype="$(echo "$mwaddrsentry" | sed "s/\.mwonofftype\./ /" | awk '{print $2}')"
  398. mwaddr="$(echo "$mwaddrsentry" | sed "s/\.mwonofftype\./ /" | awk '{print $1}')"
  399. mwidnum="$(echo "$mwaddr" | sed "s/-/ /" | awk '{print $1}')"
  400. mwaddr="$(echo "$mwaddr" | sed "s/-/ /" | awk '{print $2}')"
  401. _mwtakeaddr
  402. _mwdelete
  403. done
  404. rm -rf "$mwaccmuttdir"/[1-9]-*.muttrc "$mwcachedir" "$mwgenmuttaccs"
  405. sed -i "/\# $_MW_generated/d" "$mwmuttrc"
  406. crontab -l | sed '/mw sync/d' | crontab - >/dev/null
  407. echo "All configs and account settings have been purged."
  408. }
  409. # run after mbsync to create mutt settings for $mwaddr
  410. _mwgenmwaccmuttrc() {
  411. mwaccmaildir="$mwmaildir/$mwaddr"
  412. mwmailboxes="$(find "$mwaccmaildir/" -name cur | sed "s,$mwaccmaildir/,,g;s,/cur,,")"
  413. [ "${mwmailboxes/ /}" = "" ] && echo "no mailboxes" && return 1
  414. mwspoolfile=$(echo "$mwmailboxes" | grep -i -m 1 inbox | sed -ne 's/.*/+\0/p')
  415. [ "${mwspoolfile/ /}" = "" ] && return 1
  416. mwrecord=$(echo "$mwmailboxes" | grep -i -m 1 sent | sed -ne 's/.*/+\0/p')
  417. [ -z "$mwrecord" ] && mkdir -p "$mwaccmaildir/Sent/"{cur,new,tmp} && mwrecord="+Sent"
  418. mwpostponed=$(echo "$mwmailboxes" | grep -i -m 1 draft | sed -ne 's/.*/+\0/p')
  419. [ -z "$mwpostponed" ] && mkdir -p "$mwaccmaildir/Drafts/"{cur,new,tmp} && mwpostponed="+Drafts"
  420. mwtrash=$(echo "$mwmailboxes" | grep -i -m 1 trash | sed -ne 's/.*/+\0/p')
  421. [ -z "$mwtrash" ] && mkdir -p "$mwaccmaildir/Trash/"{cur,new,tmp} && mwtrash="+Trash"
  422. # again to reflect the change
  423. mwmailboxes="$(find "$mwaccmaildir/" -name cur | sed "s,$mwaccmaildir/,,g;s,/cur,,")"
  424. # find mwaccmuttrc ...
  425. mwaccmuttrc="$mwaccmuttdir/$(find "$mwaccmuttdir" -type f | grep -m 1 -o "[1-9]-$mwaddr.mwonofftype.$mwtype.muttrc")"
  426. if [ ! -f "$mwaccmuttrc" ]; then
  427. # new mwidnum = first one missing
  428. _mwaddrs
  429. for mwx in $(seq 1 9); do echo "$mwaddrs" | grep "$mwx:" >/dev/null 2>&1 || { export mwidnum="$mwx"; break ;}; done
  430. mwaccmuttrc="$mwaccmuttdir/$mwidnum-$mwaddr.mwonofftype.$mwtype.muttrc"
  431. else
  432. mwidnum=${mwaccmuttrc%%-*}
  433. mwidnum=${mwidnum##*/}
  434. fi
  435. # link mwaccmuttrc ...
  436. if [ "$mwtype" = "offline" ]; then
  437. ! grep "source $mwaccmuttrc" "$mwgenmuttaccs" &>/dev/null && echo "source $mwaccmuttrc" >> $mwgenmuttaccs
  438. else #online
  439. ! grep "source $mwaccmuttrc" "$mwmuttrc" &>/dev/null && echo "source $mwaccmuttrc # $_MW_generated" >> $mwmuttrc
  440. fi
  441. # (re-)generate mwaccmuttrc ...
  442. mwmuttsync=$(printf '<sync-mailbox><enter-command>source %s<enter><change-folder>!<enter>;<check-stats>' $mwaccmuttrc)
  443. cat > "$mwaccmuttrc" <<EOF
  444. # vim: filetype=muttrc
  445. # muttrc file for account $mwaddr
  446. # generated by $_MW_
  447. set from = "$mwaddr"
  448. EOF
  449. if [ "$mwtype" = "offline" ]; then
  450. cat >> "$mwaccmuttrc" <<EOF
  451. macro index gm "<shell-escape>mw $mwaddr<enter>" "sync mail $mwaddr"
  452. set folder = "$mwaccmaildir"
  453. folder-hook \$folder '$mwmuttsync'
  454. set sendmail = "msmtp -a \$from"
  455. EOF
  456. else # online
  457. if [ "${mwkind::3}" = "pop" ]; then
  458. cat >> "$mwaccmuttrc" <<EOF
  459. bind index gm fetch-mail
  460. # pop
  461. set pop_user = "$mwlogin"
  462. set pop_pass = "\`pass $mwpass\`"
  463. set pop_host = "$mwkind://$mwlogin@$mwurl:$mwport"
  464. set pop_delete = yes
  465. set folder = "$mwaccmaildir"
  466. folder-hook \$folder '$mwmuttsync'
  467. EOF
  468. else # imap
  469. mwssl=${mwkind/imap/no}
  470. cat >> "$mwaccmuttrc" <<EOF
  471. bind index gm imap-fetch-mail
  472. set folder = "$mwkind://$mwlogin@$mwurl:$mwport"
  473. set header_cache = "$mwacccachedir"
  474. set message_cachedir = \$header_cache
  475. set imap_user = "$mwlogin"
  476. set imap_pass = "\`pass $mwpass\`"
  477. account-hook \$folder 'set imap_user="$mwlogin" imap_pass="\`pass $mwpass\`"'
  478. set mbox_type = Maildir
  479. set ssl_starttls = ${mwssl/nos/yes}
  480. set ssl_force_tls = ${mwssl/nos/yes}
  481. set smtp_pass = "\`pass $mwpass\`"
  482. EOF
  483. fi # imap
  484. #smtp
  485. [ "$mwsport" = "25" ] && mwsmtp="smtp" || mwsmtp="smtps"
  486. cat >> "$mwaccmuttrc" <<EOF
  487. set smtp_url = "$mwsmtp://$mwlogin@$mwsurl:$mwsport"
  488. EOF
  489. fi #online
  490. mwboxes="$(echo "$mwmailboxes" | sed -e "s/^ //g;s/.*/\"=\0\"/g" | tr "\n" " ")"
  491. mwaccmutt="${mwaddr//[.@]/_}"
  492. cat >> "$mwaccmuttrc" <<EOF
  493. set spoolfile = "$mwspoolfile"
  494. set record = "$mwrecord"
  495. set postponed = "$mwpostponed"
  496. set trash = "$mwtrash"
  497. unmailboxes *
  498. mailboxes =$mwaccmutt ===================== $mwboxes
  499. macro index,pager i$mwidnum '$mwmuttsync' "switch to $mwaddr"
  500. EOF
  501. [ -n "$mwname" ] && cat >> "$mwaccmuttrc" <<EOF
  502. set realname = "$mwname"
  503. alias me $mwname <$mwaddr>
  504. EOF
  505. IFS=$'\n'
  506. for eqbox in $mwmailboxes; do
  507. qbox="${eqbox/\[/}"
  508. b1="${qbox::1}"
  509. box="${qbox##*/}"
  510. [ "$box" = "$qbox" ] && b2="${qbox:1:1}" || b2="${box:1:1}"
  511. boxi="$b1$b2"
  512. boxi="${boxi,,}"
  513. cat >> $mwaccmuttrc <<EOF
  514. macro index,pager i$boxi "<change-folder>=$eqbox<enter>" "go to $eqbox"
  515. macro index,pager M$boxi "<save-message>=$eqbox<enter>" "move mail to $eqbox"
  516. macro index,pager C$boxi "<copy-message>=$eqbox<enter>" "copy mail to $eqbox"
  517. EOF
  518. done
  519. unset IFS
  520. return 0
  521. }
  522. if [ "$(uname)" = "Darwin" ]; then
  523. _mwnotify() { osascript -e "display notification \"$2 in $1\" with title \"You've got Mail\" subtitle \"Account: $1\"" ;}
  524. else
  525. if type notify-send >/dev/null; then
  526. _mwnotify() { notify-send "mw" "📬 $2 new mail(s) in \`$1\` account." ;}
  527. else
  528. _mwnotify() { echo "mw: 📬 $2 new mail(s) in \`$1\` account." ;}
  529. fi
  530. fi
  531. _mwaddr() {
  532. mwaddr=$1
  533. mwaddr=${mwaddr/#\~/$HOME}
  534. mwaddr=${mwaddr#$mwmaildir/}
  535. mwaddr=${mwaddr%%/*}
  536. mkdir -p $mwmaildir/$mwaddr
  537. }
  538. _mwgenmuttaccs(){
  539. mkdir -p "$mwmuttdir" "$mwaccmuttdir"
  540. [ ! -f "$mwmuttrc" ] && echo "# vim: filetype=muttrc" > "$mwmuttrc" && echo "muttrc created."
  541. ! grep "source $mwsharerc" "$mwmuttrc" >/dev/null && echo "source $mwsharerc # $_MW_generated" >> "$mwmuttrc"
  542. ! grep "source $mwgenmuttaccs" "$mwmuttrc" >/dev/null && echo "source $mwgenmuttaccs # $_MW_generated" >> "$mwmuttrc"
  543. cat > "$mwgenmuttaccs" <<EOF
  544. # vim: filetype=muttrc
  545. # generated by $_MW_
  546. macro index gM '<shell-escape>mw<enter>' "sync all mail"
  547. EOF
  548. }
  549. _mwgatheremails() {
  550. unset mwemails
  551. _mwgenmuttaccs
  552. if [ -f "$mwmbsyncrc" ]; then
  553. for store in $(sed -ne 's/^Path\s*//p' $mwmbsyncrc); do
  554. _mwaddr "$store"
  555. mwemails+=" $mwaddr"
  556. done
  557. fi
  558. if [ -d "$mwgetmaildir" ]; then
  559. for gmrc in $mwgetmaildir/*; do
  560. [ "${gmrc#$mwgetmaildir}" = "/*" ] && break
  561. store=$(sed -ne "s/^path\s*=\s*//p" $gmrc)
  562. store=${store/#\~/$HOME}
  563. _mwaddr "$store"
  564. mkdir -p "$store"/{cur,new,tmp}
  565. mwemails+=" $mwaddr"
  566. done
  567. fi
  568. mwemails="${mwemails/ /}"
  569. }
  570. _mwsyncandnotify() {
  571. mwaccmaildir="$mwmaildir/$mwaddr"
  572. if [ -f "$mwgetmaildir/$mwaddr" ]; then
  573. getmail --rcfile=$mwaddr --getmaildir=$mwgetmaildir
  574. else
  575. mbsync -c $mwmbsyncrc $mwaddr
  576. fi
  577. [ -n "$mwnono" ] && return
  578. mwlastrun="$mwaccmaildir/.mw.lastrun"
  579. mwnew=$(find "$mwaccmaildir/INBOX/new/" "$mwaccmaildir/Inbox/new/" "$mwaccmaildir/inbox/new/" -type f -newer "$mwlastrun" 2> /dev/null)
  580. newcount=$(echo "$mwnew" | sed '/^\s*$/d' | wc -l)
  581. if [ "$newcount" -gt "0" ]; then
  582. _mwnotify "$mwaddr" "$newcount"
  583. for file in $mwnew; do
  584. # Extract subject and sender from mail.
  585. from=$(awk '/^From: / && ++n ==1,/^\<.*\>:/' "$file" | perl -CS -MEncode -ne 'print decode("MIME-Header", $_)' | \
  586. awk '{ $1=""; if (NF>=3)$NF=""; print $0 }' | sed 's/^[[:blank:]]*[\"'\''\<]*//;s/[\"'\''\>]*[[:blank:]]*$//')
  587. subject=$(awk '/^Subject: / && ++n == 1,/^\<.*\>: / && ++i == 2' "$file" | head -n-1 | perl -CS -MEncode -ne 'print decode("MIME-Header", $_)' | \
  588. sed 's/^Subject: //' | sed 's/^{[[:blank:]]*[\"'\''\<]*//;s/[\"'\''\>]*[[:blank:]]*$//' | tr -d '\n')
  589. _mwnotify "📧$from:" "$subject"
  590. done
  591. fi
  592. touch "$mwlastrun"
  593. }
  594. _mwsyncemails() {
  595. for mwaddr in $mwemails; do
  596. _mwsyncandnotify
  597. done
  598. rm $XDG_CONFIG_HOME/getmail/oldmail-* &>/dev/null
  599. echo notmuch new ...
  600. notmuch new &>/dev/null
  601. }
  602. _mwmuttemails() {
  603. for mwaddr in $mwemails; do
  604. _mwgenmwaccmuttrc
  605. done
  606. }
  607. _mwsync() {
  608. unset mwemails
  609. mwtype="offline"
  610. # Run only if user logged in (prevent cron errors)
  611. if ! pgrep -u "$USER" >/dev/null; then
  612. echo "$USER not logged in; sync will not run."
  613. return 1
  614. fi
  615. # Run only if not already running in other instance
  616. if pgrep -x mbsync >/dev/null; then
  617. echo "mbsync is running."
  618. return 1
  619. fi
  620. if pgrep -x notmuch >/dev/null; then
  621. echo "notmuch is running."
  622. return 1
  623. fi
  624. _mwcheckinternet || return 1
  625. _mwaddr "$1"
  626. mwemails="$mwaddr"
  627. [ "$mwemails" = "" ] && _mwgatheremails && _mwsyncemails && _mwmuttemails && return 0
  628. _mwsyncemails
  629. return 0
  630. }
  631. trap 'echo -e "\033[0m\n"; exit' STOP INT ABRT KILL
  632. if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
  633. if [ "$#" -gt 1 ]; then
  634. echo "Command or email or no parameter (=sync all). See --help."
  635. return 1
  636. fi
  637. if [ "$1" = "" ]; then
  638. mwnono="NO"
  639. _mwsync
  640. else
  641. case "$1" in
  642. list|ls) _mwlist ;;
  643. add) _mwadd ;;
  644. pass) _mwpick "change the password of" && _mwgetpass ;;
  645. remove|rm) _mwpick remove && _mwconfirm "remove the \`$mwaddr\` profile" && _mwdelete ;;
  646. purge) _mwpurge ;;
  647. cron) _mwcron ;;
  648. sync) _mwsync ;;
  649. *@*) _mwsync $1 ;;
  650. --version|-v) echo "$_MW_ $VERSION" ;;
  651. --help|-h) cat <<EOF
  652. mw: $_MW_ $VERSION, auto-configure and sync email accounts for mutt,
  653. including mutt-independent sync of mail with \`isync\` or download of POP3 mail with \`getmail\`.
  654. Commands:
  655. add Add and configure an email address (9 max.)
  656. list List configured accounts
  657. remove Pick an account to remove
  658. purge Remove all accounts and settings
  659. cron Enable or disable an autosync via cronjob
  660. sync sync/download mail based on config in $mwmbsyncrc and $mwgetmaildir
  661. --help|-h Print this message
  662. --version|-v Prints version
  663. With no parameter all configured emails are synced and all account muttrc's are created.
  664. With a parameter containing a @, an mail is assumed and that account is synced.
  665. Config requirements:
  666. - mbsyncrc: "Path" ends in email
  667. - getmail: config file name = email, "path" ends in email
  668. EOF
  669. esac
  670. exit $?
  671. fi
  672. fi