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

424 строки
16 KiB

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