Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 

389 rader
14 KiB

  1. #!/bin/sh
  2. prefix="/usr/local"
  3. maildir="${XDG_DATA_HOME:-$HOME/.local/share}/mail"
  4. muttshare="$prefix/share/mutt-wizard"
  5. cachedir="${XDG_CACHE_HOME:-$HOME/.cache}/mutt-wizard"
  6. muttrc="${XDG_CONFIG_HOME:-$HOME/.config}/mutt/muttrc"
  7. accdir="${XDG_CONFIG_HOME:-$HOME/.config}/mutt/accounts"
  8. msmtprc="${XDG_CONFIG_HOME:-$HOME/.config}/msmtp/config"
  9. msmtplog="${XDG_CONFIG_HOME:-$HOME/.config}/msmtp/msmtp.log"
  10. mbsyncrc="${MBSYNCRC:-$HOME/.mbsyncrc}"
  11. mpoprc="${XDG_CONFIG_HOME:-$HOME/.config}/mpop/config"
  12. alias mbsync='mbsync -c "$mbsyncrc"'
  13. 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/"; do
  14. [ -f "$x" ] && sslcert="$x" && break
  15. done || { echo "CA Certificate not found. Please install one or link it to /etc/ssl/certs/ca-certificates.crt" && exit 1 ;}
  16. checkbasics() { command -V gpg >/dev/null 2>&1 && GPG="gpg" || GPG="gpg2"
  17. PASSWORD_STORE_DIR="${PASSWORD_STORE_DIR:-$HOME/.password-store}"
  18. [ -r "$PASSWORD_STORE_DIR/.gpg-id" ] &&
  19. "$GPG" --list-secret-keys "$(cat "$PASSWORD_STORE_DIR/.gpg-id")" >/dev/null 2>&1 || {
  20. echo "First run \`pass init <yourgpgemail>\` to set up a password archive."
  21. echo "(If you don't already have a GPG key pair, first run \`$GPG --full-generate-key\`.)"
  22. exit 1 ;} ;}
  23. getaccounts() { accounts="$(find -L "$accdir" -type f 2>/dev/null | grep -o "[0-9]-.*.muttrc" | sed "s/-/: /;s/\.muttrc$//" | sort -n)" ;}
  24. list() { getaccounts && [ -n "$accounts" ] && echo "$accounts" || exit 1 ;}
  25. prepmsmtp() { echo "account $fulladdr
  26. host $smtp
  27. port ${sport:-587}
  28. from $fulladdr
  29. user $login
  30. passwordeval \"pass $fulladdr\"
  31. auth ${auth:-on}
  32. ${tlsline:-tls on}
  33. tls_trust_file $sslcert
  34. logfile $msmtplog
  35. " >> "$msmtprc"
  36. # On Ubuntu/Debian, a link is needed since they use an older version.
  37. command -V apt-get >/dev/null 2>&1 && ln -s "$msmtprc" "$HOME/.msmtprc" 2>/dev/null
  38. }
  39. prepmbsync() { mkdir -p "${mbsyncrc%/*}"
  40. echo "
  41. IMAPStore $fulladdr-remote
  42. Host $imap
  43. Port ${iport:-993}
  44. User $login
  45. PassCmd \"pass $fulladdr\"
  46. AuthMechs LOGIN
  47. SSLType ${imapssl:-IMAPS}
  48. CertificateFile $sslcert
  49. MaildirStore $fulladdr-local
  50. Subfolders Verbatim
  51. Path ${XDG_DATA_HOME:-$HOME/.local/share}/mail/$fulladdr/
  52. Inbox ${XDG_DATA_HOME:-$HOME/.local/share}/mail/$fulladdr/${inbox:-INBOX}
  53. Channel $fulladdr
  54. Expunge Both
  55. Master :$fulladdr-remote:
  56. Slave :$fulladdr-local:
  57. Patterns * !\"[Gmail]/All Mail\"
  58. Create Both
  59. SyncState *
  60. MaxMessages ${maxmes:-0}
  61. ExpireUnread no
  62. # End profile
  63. " >> "$mbsyncrc" ;}
  64. prepmpop() { mkdir -p "${mpoprc%/*}"
  65. echo "
  66. account $fulladdr
  67. tls on
  68. user $login
  69. host $imap
  70. delivery maildir ${XDG_DATA_HOME:-$HOME/.local/share}/mail/$fulladdr/${inbox:-INBOX}
  71. passwordeval pass $fulladdr
  72. " >> "$mpoprc" ;}
  73. prepmutt() { echo "# vim: filetype=neomuttrc
  74. # muttrc file for account $fulladdr
  75. set realname = \"$realname\"
  76. set from = \"$fulladdr\"
  77. set sendmail = \"msmtp -a $fulladdr\"
  78. alias me $realname <$fulladdr>
  79. set folder = \"$folder\"
  80. set header_cache = $cachedir/$fulladdr/headers
  81. set message_cachedir = $cachedir/$fulladdr/bodies
  82. set mbox_type = Maildir
  83. $extra
  84. bind index,pager gi noop
  85. bind index,pager gs noop
  86. bind index,pager gd noop
  87. bind index,pager ga noop
  88. bind index,pager gS noop
  89. bind index,pager gj noop
  90. bind index,pager gt noop
  91. bind index,pager Mi noop
  92. bind index,pager Ms noop
  93. bind index,pager Md noop
  94. bind index,pager Ma noop
  95. bind index,pager MS noop
  96. bind index,pager Mj noop
  97. bind index,pager Mt noop
  98. bind index,pager Ci noop
  99. bind index,pager Cs noop
  100. bind index,pager Cd noop
  101. bind index,pager Ca noop
  102. bind index,pager CS noop
  103. bind index,pager Cj noop
  104. bind index,pager Ct noop
  105. bind index,pager gg noop
  106. bind index,pager g noop
  107. bind index,pager M noop
  108. bind index,pager C noop
  109. bind index gg first-entry
  110. unmailboxes *
  111. unalternates *
  112. unset signature
  113. unset hostname
  114. unmy_hdr Organization
  115. unmacro index o
  116. $synccmd
  117. " > "$accdir/$idnum-$fulladdr.muttrc"
  118. [ ! -f "$muttrc" ] && echo "# vim: filetype=neomuttrc" > "$muttrc"
  119. ! grep -q "^source.*mutt-wizard.muttrc" "$muttrc" && echo "source $muttshare/mutt-wizard.muttrc" >> "$muttrc"
  120. ! grep "^source.*.muttrc" "$muttrc" | grep -qv "$muttshare/mutt-wizard.muttrc" && echo "source $accdir/$idnum-$fulladdr.muttrc" >> "$muttrc"
  121. echo "macro index,pager i$idnum '<sync-mailbox><enter-command>source $accdir/$idnum-$fulladdr.muttrc<enter><change-folder>!<enter>;<check-stats>' \"switch to $fulladdr\"" >> "$muttrc"
  122. }
  123. getprofiles() { \
  124. mkdir -p "${muttrc%/*}" "$accdir" "$cachedir/$fulladdr/bodies" "${XDG_CONFIG_HOME:-$HOME/.config}/msmtp"
  125. unset msmtp_header msmtp_profile mutt_profile mbsync_profile
  126. case "$iport" in
  127. 1143) imapssl=None ;;
  128. 143) imapssl=STARTTLS ;;
  129. esac
  130. case "$type" in
  131. online) folder="imaps://$login@$imap:${iport:-993}"
  132. extra="set imap_user = \"$login\"
  133. set imap_pass = \"\`pass $fulladdr\`\"
  134. set ssl_starttls = yes
  135. set ssl_force_tls = yes"
  136. ;;
  137. pop) synccmd="macro index o \"<shell-escape>mpop $fulladdr<enter>\" \"run mpop to get $fulladdr's mail\""
  138. folder="$maildir/$fulladdr"
  139. prepmpop ;;
  140. *) synccmd="macro index o \"<shell-escape>mw -y $fulladdr<enter>\" \"run mbsync to sync $fulladdr\""
  141. folder="$maildir/$fulladdr"
  142. prepmbsync ;;
  143. esac
  144. prepmsmtp
  145. prepmutt
  146. prepnotmuch # Create a notmuch config file if not present already.
  147. }
  148. parsedomains(){ serverinfo="$(grep "^${fulladdr#*@}" "$muttshare/domains.csv" 2>/dev/null)"
  149. [ -z "$serverinfo" ] && serverinfo="$(grep "$(echo "${fulladdr#*@}" | sed "s/\.[^\.]*$/\.\\\*/")" "$muttshare/domains.csv" 2>/dev/null)"
  150. IFS=, read -r service imapsugg iportsugg smtpsugg sportsugg <<EOF
  151. $serverinfo
  152. EOF
  153. imap="${imap:-$imapsugg}"
  154. smtp="${smtp:-$smtpsugg}"
  155. sport="${sport:-$sportsugg}"
  156. iport="${iport:-$iportsugg}"
  157. }
  158. delete() { if [ -z "${fulladdr+x}" ]; then
  159. echo "Select the account you would like to delete (by number):"
  160. list || exit 1
  161. read -r input
  162. match="^$input:"
  163. else
  164. match=" $fulladdr$"
  165. getaccounts
  166. fi
  167. fulladdr="$(echo "$accounts" | grep "$match" | cut -f2 -d' ')"
  168. [ -z "$fulladdr" ] && echo "$fulladdr is not a valid account name." && return 1
  169. sed -ibu "/IMAPStore $fulladdr-remote$/,/# End profile/d" "$mbsyncrc" 2>/dev/null ; rm -f "$mbsyncrc"bu
  170. rm -rf "${cachedir:?}/${fulladdr:?}" "$accdir/"[1-9]"-$fulladdr.muttrc"
  171. sed -ibu "/[0-9]-$fulladdr.muttrc/d" "$muttrc" 2>/dev/null; rm -f "$muttrc"bu
  172. sed -ibu "/account $fulladdr$/,/^\(\s*$\|account\)/d" "$msmtprc" 2>/dev/null; rm -f "$msmtprc"bu
  173. sed -ibu "/account $fulladdr$/,/^\(\s*$\|account\)/d" "$mpoprc" 2>/dev/null; rm -f "$mpoprc"bu
  174. pass rm -f "$fulladdr" >/dev/null 2>&1
  175. [ -n "${purge+x}" ] && rm -rf "${maildir:?}/${fulladdr:?}"
  176. # Get rid of those multiple newlines because I don't know awk well enough to do it by default lol.
  177. for file in "$msmtprc" "$mbsyncrc" "$mpoprc"; do
  178. tr '\n' '|' 2>/dev/null < "$file" | sed "s/||\+/||/g" | tr '|' '\n' >> "$file"bu
  179. mv -f "$file"bu "$file"
  180. done
  181. }
  182. askinfo() { \
  183. [ -z "$fulladdr" ] && echo "Give the full email address to add:" &&
  184. read -r fulladdr
  185. while ! echo "$fulladdr" | grep -qE "^.+@.+\.[A-Za-z]+$"; do
  186. echo "\`$fulladdr\` is not a valid email address. Please retype the address:"
  187. read -r fulladdr
  188. done
  189. getaccounts; echo "$accounts" | grep -q "\s$fulladdr$" 2>/dev/null &&
  190. { echo "$fulladdr has already been added" && exit 1 ;}
  191. { [ -z "$imap" ] || [ -z "$smtp" ] ;} && parsedomains
  192. [ -z "$imap" ] && echo "Give your email server's IMAP address (excluding the port number):" &&
  193. read -r imap
  194. [ -z "$smtp" ] && echo "Give your email server's SMTP address (excluding the port number):" &&
  195. read -r smtp
  196. [ "$sport" = 465 ] && tlsline="tls_starttls off"
  197. [ -z "$realname" ] && realname="${fulladdr%%@*}"
  198. login="${login:-$fulladdr}"
  199. if [ -n "${password+x}" ]; then
  200. createpass
  201. else
  202. getpass
  203. fi
  204. }
  205. createpass() { echo "$password" > "$PASSWORD_STORE_DIR/$fulladdr"
  206. "$GPG" -qer "$(cat "$PASSWORD_STORE_DIR/.gpg-id")" "$PASSWORD_STORE_DIR/$fulladdr"
  207. rm -f "$PASSWORD_STORE_DIR/$fulladdr" ;}
  208. getpass() { while : ; do pass rm -f "$fulladdr" >/dev/null 2>&1
  209. pass insert -f "$fulladdr" && break; done ;}
  210. formatShortcut() { toappend="$toappend
  211. macro index,pager g$1 \"<change-folder>=$3<enter>\" \"go to $2\"
  212. macro index,pager M$1 \";<save-message>=$3<enter>\" \"move mail to $2\"
  213. macro index,pager C$1 \";<copy-message>=$3<enter>\" \"copy mail to $2\"" ;}
  214. setBox() { toappend="$toappend
  215. set $1 = \"+$2\"" ;}
  216. getboxes() { if [ -n "${force+x}" ] ; then
  217. mailboxes="$(printf "INBOX\\nDrafts\\nJunk\\nTrash\\nSent\\nArchive")"
  218. else
  219. info="$(curl --location-trusted -s -m 5 --user "$login:$(pass "$fulladdr")" --url "${protocol:-imaps}://$imap:${iport:-993}")"
  220. [ -z "$info" ] && echo "Log-on not successful." && return 1
  221. mailboxes="$(echo "$info" | grep -v HasChildren | sed "s/.*\" //;s/\"//g" | tr -d ' ')"
  222. fi
  223. [ "$type" = "pop" ] && mailboxes="INBOX"
  224. getaccounts; for x in $(seq 1 9); do echo "$accounts" | grep -q "^$x:" || { export idnum="$x"; break ;}; done
  225. toappend="mailboxes $(echo "$mailboxes" | sed "s/^/\"=/;s/$/\"/" | paste -sd ' ' - )"
  226. for x in $mailboxes; do
  227. case "$x" in
  228. *[Ss][Ee][Nn][Tt]*) setBox record "$x"; formatShortcut s sent "$x" ;;
  229. *[Dd][Rr][Aa][Ff][Tt][Ss]*) setBox postponed "$x"; formatShortcut d drafts "$x" ;;
  230. *[Tt][Rr][Aa][Ss][Hh]*) formatShortcut t trash "$x"; setBox trash "$x" ;;
  231. *[Jj][Uu][Nn][Kk]*) formatShortcut j junk "$x" ;;
  232. *[Aa][Rr][Cc][Hh][Ii][Vv][Ee]*) formatShortcut a archive "$x" ;;
  233. *[Ss][Pp][Aa][Mm]*) formatShortcut S spam "$x" ;;
  234. *[Ii][Nn][Bb][Oo][Xx]*) formatShortcut i inbox "$x"; setBox spoolfile "$x" inbox="$x" ;;
  235. esac
  236. done
  237. }
  238. finalize() { echo "$toappend" >> "$accdir/$idnum-$fulladdr.muttrc"
  239. [ "$type" != "online" ] && echo "$mailboxes" | xargs -I {} mkdir -p "$maildir/$fulladdr/{}/cur" "$maildir/$fulladdr/{}/tmp" "$maildir/$fulladdr/{}/new"
  240. echo "$fulladdr (account #$idnum) added successfully."
  241. command -V urlview >/dev/null 2>&1 && [ ! -f "$HOME/.urlview" ] && echo "COMMAND \$BROWSER" > "$HOME/.urlview"
  242. return 0 ;}
  243. prepnotmuch() { \
  244. [ -z "$NOTMUCH_CONFIG" ] && NOTMUCH_CONFIG="$HOME/.notmuch-config"
  245. [ -f "$NOTMUCH_CONFIG" ] && return 0
  246. nmbasic="[database]
  247. path=$maildir
  248. [user]
  249. name=$realname
  250. primary_email=$fulladdr
  251. [new]
  252. tags=unread;inbox;
  253. ignore=.mbsyncstate;.uidvalidity
  254. [search]
  255. exclude_tags=deleted;spam;
  256. [maildir]
  257. synchronize_flags=true
  258. [crypto]
  259. gpg_path=$GPG"
  260. echo "$nmbasic" > "$NOTMUCH_CONFIG" ;}
  261. togglecron() { cron="$(mktemp)"
  262. crontab -l > "$cron"
  263. if grep -q mailsync "$cron"; then
  264. echo "Removing automatic mailsync..."
  265. sed -ibu /mailsync/d "$cron"; rm -f "$cron"bu
  266. else
  267. echo "Adding automatic mailsync every ${cronmin:-10} minutes..."
  268. echo "*/${cronmin-10} * * * * $prefix/bin/mailsync" >> "$cron"
  269. fi &&
  270. crontab "$cron"; rm -f "$cron" ;}
  271. setact() { if [ -n "${action+x}" ] && [ "$action" != "$1" ]; then
  272. echo "Running $1 with $action..."
  273. echo "Incompatible options given. Only one action may be specified per run."
  274. return 1
  275. else
  276. action="$1"
  277. fi; }
  278. mwinfo() { cat << EOF
  279. mw: mutt-wizard, auto-configure email accounts for mutt
  280. including downloadable mail with \`isync\`.
  281. Main actions:
  282. -a your@email.com Add an email address
  283. -l List email addresses configured
  284. -d Remove an already added address
  285. -D your@email.com Force remove account without confirmation
  286. -y your@email.com Sync mail for account by name
  287. -Y Sync mail for all accounts
  288. -t number Toggle automatic mailsync every <number> minutes
  289. -T Toggle automatic mailsync
  290. Options allowed with -a:
  291. -u Account login name if not full address
  292. -n "Real name" to be on the email account
  293. -i IMAP/POP server address
  294. -I IMAP/POP server port
  295. -s SMTP server address
  296. -S SMTP server port
  297. -x Password for account (recommended to be in double quotes)
  298. -p Install for a Protonmail account.
  299. -P Add for a POP server instead of IMAP.
  300. -X Delete an account's local email too when deleting.
  301. -o Configure address, but keep mail online.
  302. -f Assume typical English mailboxes without attempting log-on.
  303. NOTE: Once at least one account is added, you can run
  304. \`mbsync -a\` to begin downloading mail.
  305. To change an account's password, run \`pass edit your@email.com\`.
  306. EOF
  307. }
  308. while getopts "fpPXlhodTYD:y:i:I:s:S:u:a:n:x:m:t:" o; do case "${o}" in
  309. l) setact list || exit 1 ;;
  310. d) setact delete || exit 1 ;;
  311. D) setact delete || exit 1 ; fulladdr="$OPTARG" ;;
  312. y) setact sync || exit 1 ; fulladdr="$OPTARG" ;;
  313. Y) setact sync || exit 1 ;;
  314. a) setact add || exit 1 ; fulladdr="$OPTARG" ;;
  315. i) setact add || exit 1 ; imap="$OPTARG" ;;
  316. I) setact add || exit 1 ; iport="$OPTARG" ;;
  317. s) setact add || exit 1 ; smtp="$OPTARG" ;;
  318. S) setact add || exit 1 ; sport="$OPTARG" ;;
  319. u) setact add || exit 1 ; login="$OPTARG" ;;
  320. n) setact add || exit 1 ; realname="$OPTARG" ;;
  321. m) setact add || exit 1 ; maxmes="$OPTARG" ;;
  322. o) setact add || exit 1 ; type="online" ;;
  323. P) setact add || exit 1 ; type="pop"; protocol="pop3s" ; iport="${iport:-995}" ;;
  324. f) setact add || exit 1 ; force=True ;;
  325. x) setact add || exit 1 ; password="$OPTARG" ;;
  326. X) setact delete || exit 1 ; purge=True ;;
  327. t) setact toggle || exit 1 ; cronmin="$OPTARG" ;;
  328. T) setact toggle || exit 1 ;;
  329. p) echo "NOTE: Protonmail users must install and configure Protonmail Bridge first for the first sync to work."
  330. protocol="imap"
  331. imap="127.0.0.1"
  332. iport="1143"
  333. smtp="127.0.0.1"
  334. sport="1025"
  335. auth="login"
  336. tlsline="tls_fingerprint $(msmtp --serverinfo --host=$smtp --port=$sport --tls --tls-certcheck=off | awk '/SHA256:/ {print $2}')"
  337. setact add || exit 1
  338. ;;
  339. *) mwinfo; exit 1 ;;
  340. esac done
  341. case "$action" in
  342. list) list ;;
  343. add) checkbasics && askinfo && getboxes && getprofiles && finalize ;;
  344. delete) delete ;;
  345. sync) mailsync $fulladdr ;;
  346. toggle) togglecron ;;
  347. *) mwinfo; exit 1 ;;
  348. esac