您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

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