Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

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