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.
 
 
 
 

750 lines
25 KiB

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