* .emacs.d/lisp/bandali-gnus.el: Tweak gnus-posting-styles.
[~bandali/configs] / .emacs.d / lisp / bandali-gnus.el
1 ;;; bandali-gnus.el --- bandali's Gnus setup -*- lexical-binding: t; -*-
2
3 ;; Copyright (C) 2018-2022 Amin Bandali
4
5 ;; Author: Amin Bandali <bandali@gnu.org>
6 ;; Keywords: mail, news
7
8 ;; This program is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation, either version 3 of the License, or
11 ;; (at your option) any later version.
12
13 ;; This program is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
17
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
20
21 ;;; Commentary:
22
23 ;; My trusty super awesome Gnus setup.
24
25 ;;; Code:
26
27 (defvar b/maildir (expand-file-name "~/mail/"))
28 (with-eval-after-load 'recentf
29 (add-to-list 'recentf-exclude b/maildir))
30
31 (defvar b/gnus-init-file (b/etc "gnus"))
32
33 (eval-when-compile
34 (progn
35 (defvar nndraft-directory)
36 (defvar gnus-read-newsrc-file)
37 (defvar gnus-save-newsrc-file)
38 (defvar gnus-gcc-mark-as-read)
39 (defvar nnmail-split-abbrev-alist)))
40
41 (declare-function article-make-date-line "gnus-art" (date type))
42
43 (setq
44 mail-user-agent 'gnus-user-agent
45 read-mail-command 'gnus
46
47 gnus-select-method '(nnnil "")
48 gnus-secondary-select-methods
49 `(,@(if (string= (system-name) "darya")
50 '((nnimap
51 "canonical"
52 (nnimap-stream plain)
53 (nnimap-address "127.0.0.1")
54 (nnimap-server-port 143)
55 (nnimap-authenticator plain)
56 (nnimap-user "bandali@canonical.local")))
57 '((nnimap
58 "kelar"
59 (nnimap-stream plain)
60 (nnimap-address "127.0.0.1")
61 (nnimap-server-port 143)
62 (nnimap-authenticator plain)
63 (nnimap-user "bandali@kelar.local"))
64 (nnimap
65 "shemshak"
66 (nnimap-stream plain)
67 (nnimap-address "127.0.0.1")
68 (nnimap-server-port 143)
69 (nnimap-authenticator plain)
70 (nnimap-user "bandali@shemshak.local"))
71 (nnimap
72 "gnu"
73 (nnimap-stream plain)
74 (nnimap-address "127.0.0.1")
75 (nnimap-server-port 143)
76 (nnimap-authenticator plain)
77 (nnimap-user "bandali@gnu.local")
78 (nnimap-inbox "INBOX")
79 (nnimap-split-methods 'nnimap-split-fancy)
80 (nnimap-split-fancy
81 (|
82 ;; (: gnus-registry-split-fancy-with-parent)
83 ;; (: gnus-group-split-fancy "INBOX" t "INBOX")
84 ;; spam
85 ("X-Spam_action" "reject" "Junk")
86 ;; keep debbugs emails in INBOX
87 (list ".*<\\(.*\\)\\.debbugs\\.gnu\\.org>.*" "INBOX")
88 ;; list moderation emails
89 (from ".+-\\(owner\\|bounces\\)@\\(non\\)?gnu\\.org" "listmod")
90 ;; gnu
91 (list ".*<\\(.*\\)\\.\\(non\\)?gnu\\.org>.*" "l.\\1")
92 ;; fsf
93 (list ".*<\\(.*\\)\\.fsf\\.org>.*" "l.\\1")
94 ;; debian
95 (list ".*<\\(.*\\)\\.alioth-lists\\.debian\\.net>.*" "l.\\1")
96 ;; gnus
97 (list ".*<\\(.*\\)\\.gnus\\.org>.*" "l.\\1")
98 ;; libreplanet
99 (list ".*<\\(.*\\)\\.libreplanet\\.org>.*" "l.\\1")
100 ;; iana (e.g. tz-announce)
101 (list ".*<\\(.*\\)\\.iana\\.org>.*" "l.\\1")
102 ;; mailop
103 (list ".*<\\(.*\\)\\.mailop\\.org>.*" "l.\\1")
104 ;; sdlu
105 (list ".*<\\(.*\\)\\.spammers\\.dontlike\\.us>.*" "l.sdlu")
106 ;; bitfolk
107 (from ".*@\\(.+\\)?bitfolk\\.com>.*" "bitfolk")
108 ;; haskell
109 (list ".*<\\(.*\\)\\.haskell\\.org>.*" "l.\\1")
110 ;; *.lists.sr.ht, omitting one dot if present
111 ;; add more \\.?\\([^.]*\\) if needed
112 (list ".*<~\\(.*\\)/\\([^.]*\\)\\.?\\([^.]*\\)\\.lists\\.sr\\.ht>.*" "l.~\\1.\\2\\3")
113 ;; webmasters
114 (from "webmasters\\(-comment\\)?@gnu\\.org" "webmasters")
115 ;; other
116 ("subject" "nagios-fsf:.*" "nagios-fsf")
117 (list ".*atreus.freelists.org" "l.atreus")
118 (list ".*deepspec.lists.cs.princeton.edu" "l.deepspec")
119 ;; (list ".*haskell-art.we.lurk.org" "l.haskell.art") ;d
120 ;; (list ".*notmuch.notmuchmail.org" "l.notmuch") ;u
121 (list ".*dev.lists.parabola.nu" "l.parabola-dev")
122 ;; ----------------------------------
123 ;; legend: (u)nsubscribed | (d)ead
124 ;; ----------------------------------
125 ;; otherwise, leave mail in INBOX
126 "INBOX")))
127 (nnimap
128 "csc"
129 (nnimap-stream plain)
130 (nnimap-address "127.0.0.1")
131 (nnimap-server-port 143)
132 (nnimap-authenticator plain)
133 (nnimap-user "abandali@csclub.uwaterloo.local")
134 (nnimap-inbox "INBOX")
135 (nnimap-split-methods 'nnimap-split-fancy)
136 (nnimap-split-fancy
137 (|
138 ;; cron reports and other messages from root
139 (from "root@\\(.*\\.\\)?csclub\\.uwaterloo\\.ca" "INBOX")
140 ;; spam
141 ("X-Spam-Flag" "YES" "Junk")
142 ;; catch-all
143 "INBOX")))
144 (nnimap
145 "sfl"
146 (nnimap-stream plain)
147 (nnimap-address "127.0.0.1")
148 (nnimap-server-port 143)
149 (nnimap-authenticator plain)
150 (nnimap-user "amin.bandali@savoirfairelinux.local")))))
151 gnus-message-archive-group "nnimap+gnu:INBOX"
152 gnus-parameters
153 '(("l\\.deepspec"
154 (to-address . "deepspec@lists.cs.princeton.edu")
155 (to-list . "deepspec@lists.cs.princeton.edu")
156 (list-identifier . "\\[deepspec\\]"))
157 ("l\\.fencepost-users"
158 (to-address . "fencepost-users@gnu.org")
159 (to-list . "fencepost-users@gnu.org")
160 (list-identifier . "\\[Fencepost-users\\]"))
161 ("l\\.haskell-cafe"
162 (to-address . "haskell-cafe@haskell.org")
163 (to-list . "haskell-cafe@haskell.org")
164 (list-identifier . "\\[Haskell-cafe\\]"))
165 ("gnu.*"
166 (gcc-self . t)))
167 ;; nnimap-record-commands t
168 ;; gnus-large-newsgroup 50
169 ;; gnus-process-mark-toggle t
170 gnus-home-directory (b/var "gnus/")
171 gnus-directory (concat gnus-home-directory "news/")
172 message-directory (concat gnus-home-directory "mail/")
173 nndraft-directory (concat gnus-home-directory "drafts/")
174 gnus-save-newsrc-file nil
175 gnus-read-newsrc-file nil
176 gnus-search-use-parsed-queries t
177 gnus-interactive-exit nil
178 gnus-gcc-mark-as-read t)
179
180 (with-eval-after-load 'gnus
181 (when (version< emacs-version "27")
182 (with-eval-after-load 'nnmail
183 (add-to-list
184 'nnmail-split-abbrev-alist
185 '(list . "list-id\\|list-post\\|x-mailing-list\\|x-beenthere\\|x-loop")
186 t)))
187
188 (setq gnus-user-agent '(emacs gnus type))
189
190 ;; (require 'gnus-registry)
191 ;; (setq gnus-registry-max-entries 2500)
192 ;; (setq gnus-registry-ignored-groups
193 ;; (append gnus-registry-ignored-groups
194 ;; '(("^nnimap:gnu\\.l" t)
195 ;; ("webmasters$" t))))
196 ;; (gnus-registry-initialize)
197
198 (with-eval-after-load 'recentf
199 (add-to-list 'recentf-exclude gnus-home-directory))
200
201 ;; hooks
202 (add-hook 'gnus-group-mode-hook #'gnus-topic-mode)
203 (add-hook 'gnus-group-mode-hook #'gnus-agent-mode))
204 ;; global key bindings
205 (global-set-key (kbd "C-c g") #'gnus-plugged)
206 (global-set-key (kbd "C-c G") #'gnus-unplugged)
207
208 (with-eval-after-load 'gnus-art
209 (setq
210 gnus-buttonized-mime-types '("multipart/\\(signed\\|encrypted\\)")
211 gnus-sorted-header-list '("^From:"
212 "^X-RT-Originator"
213 "^Newsgroups:"
214 "^Subject:"
215 "^Date:"
216 "^Envelope-To:"
217 "^Followup-To:"
218 "^Reply-To:"
219 "^Organization:"
220 "^Summary:"
221 "^Abstract:"
222 "^Keywords:"
223 "^To:"
224 "^[BGF]?Cc:"
225 "^Posted-To:"
226 "^Mail-Copies-To:"
227 "^Mail-Followup-To:"
228 "^Apparently-To:"
229 "^Resent-From:"
230 "^User-Agent:"
231 "^X-detected-operating-system:"
232 "^X-Spam_action:"
233 "^X-Spam_bar:"
234 "^Message-ID:"
235 ;; "^References:"
236 "^List-Id:"
237 "^Gnus-Warning:")
238 gnus-visible-headers (mapconcat #'identity
239 gnus-sorted-header-list
240 "\\|")
241 ;; local-lapsed article dates
242 ;; from https://www.emacswiki.org/emacs/GnusFormatting#toc11
243 gnus-article-date-headers '(user-defined)
244 gnus-article-time-format
245 (lambda (time)
246 (let* ((date (format-time-string "%a, %d %b %Y %T %z" time))
247 (local (article-make-date-line date 'local))
248 (combined-lapsed (article-make-date-line date
249 'combined-lapsed))
250 (lapsed (progn
251 (string-match " (.+" combined-lapsed)
252 (match-string 0 combined-lapsed))))
253 (concat local lapsed))))
254 ;; local key bindings
255 (declare-function org-store-link "ol" (arg &optional interactive?))
256 (define-key gnus-article-mode-map (kbd "M-L") #'org-store-link))
257
258 (with-eval-after-load 'gnus-sum
259 (setq gnus-thread-sort-functions '(gnus-thread-sort-by-number
260 gnus-thread-sort-by-subject
261 gnus-thread-sort-by-date))
262 (with-eval-after-load 'message
263 (setq gnus-ignored-from-addresses message-dont-reply-to-names))
264 ;; local key bindings
265 (define-key gnus-summary-mode-map (kbd "M-L") #'org-store-link)
266 ;; (define-key gnus-summary-mode-map (kbd "r")
267 ;; #'gnus-summary-reply-with-original)
268 ;; (define-key gnus-summary-mode-map (kbd "R")
269 ;; #'gnus-summary-wide-reply-with-original)
270 (defvar b/gnus-summary-prefix-map)
271 (define-prefix-command 'b/gnus-summary-prefix-map)
272 (define-key gnus-summary-mode-map (kbd "v")
273 'b/gnus-summary-prefix-map)
274 (define-key b/gnus-summary-prefix-map (kbd "r")
275 #'gnus-summary-reply)
276 (define-key b/gnus-summary-prefix-map (kbd "w")
277 #'gnus-summary-wide-reply)
278 (define-key b/gnus-summary-prefix-map (kbd "v")
279 #'gnus-summary-show-raw-article))
280 ;; hooks
281 (add-hook 'gnus-summary-mode-hook #'b/no-mouse-autoselect-window)
282
283 (defvar b/sfl-p nil)
284 (with-eval-after-load 'gnus-msg
285 (let ((bandali "Amin Bandali (https://kelar.org/~bandali)"))
286 (defvar b/csc-signature
287 (mapconcat
288 #'identity
289 `(,bandali
290 "Systems Committee <syscom@csclub.uwaterloo.ca>"
291 "Computer Science Club of the University of Waterloo")
292 "\n"))
293 (defvar b/sfl-signature
294 (mapconcat
295 #'identity
296 `(,bandali
297 "Volunteer, Savoir-faire Linux"
298 "jami:bandali")
299 "\n")))
300 (setq
301 gnus-message-replysign t
302 gnus-posting-styles
303 '((".*"
304 (address "bandali@gnu.org")
305 ("X-Message-SMTP-Method" "smtp fencepost.gnu.org 587"))
306 ((header "subject" "ThankCRM")
307 (to "webmasters-comment@gnu.org")
308 (body ""))
309 ("nnimap\\+kelar:.*"
310 (address "bandali@kelar.org")
311 ("X-Message-SMTP-Method" "smtp mail.kelar.org 587")
312 (gcc "nnimap+kelar:Sent"))
313 ("nnimap\\+shemshak:.*"
314 (address "amin@shemshak.org")
315 ("X-Message-SMTP-Method" "smtp mail.shemshak.org 587")
316 (gcc "nnimap+shemshak:Sent"))
317 ("nnimap\\+canonical:.*"
318 (address "bandali@canonical.com")
319 ("X-Message-SMTP-Method" "smtp smtp.canonical.com 587")
320 (signature nil)
321 (gcc "nnimap+canonical:Sent"))
322 ((header "to" "amin\\.bandali@canonical\\.com")
323 (address "amin.bandali@canonical.com"))
324 ((header "cc" "amin\\.bandali@canonical\\.com")
325 (address "amin.bandali@canonical.com"))
326 ((header "list-id" ".*\\.lists.ubuntu.com")
327 (address "bandali@ubuntu.com")
328 ("X-Message-SMTP-Method" "smtp mail.kelar.org 587"))
329 ("nnimap\\+csc:.*"
330 (address "bandali@csclub.uwaterloo.ca")
331 ("X-Message-SMTP-Method" "smtp mail.csclub.uwaterloo.ca 587")
332 (signature b/csc-signature)
333 (gcc "nnimap+csc:Sent"))
334 ("nnimap\\+sfl:.*"
335 (address "amin.bandali@savoirfairelinux.com")
336 ("X-Message-SMTP-Method" "smtp mail.savoirfairelinux.com 587")
337 (signature b/sfl-signature)
338 (eval (setq-local b/sfl-p t))
339 (gcc "nnimap+sfl:Sent")))))
340 ;; hooks
341 ;; (with-eval-after-load 'gnus
342 ;; (add-hook 'gnus-message-setup-hook
343 ;; (lambda ()
344 ;; (unless (or (mml-secure-is-encrypted-p)
345 ;; b/sfl-p)
346 ;; (mml-secure-message-sign)))))
347
348 (with-eval-after-load 'gnus-topic
349 (setq
350 gnus-topic-line-format "%i[ %A: %(%{%n%}%) ]%v\n"
351 gnus-topic-topology
352 `(("Gnus" visible nil nil)
353 (("misc" visible nil nil))
354 ,@(if (string= (system-name) "darya")
355 '((("canonical" visible nil nil)))
356 '((("csc" visible nil nil))
357 (("kelar" visible nil nil))
358 (("shemshak" visible nil nil))
359 (("gnu" visible nil nil))
360 (("old-gnu" visible nil nil))
361 (("sfl" visible nil nil)))))))
362
363 (with-eval-after-load 'gnus-agent
364 (setq gnus-agent-synchronize-flags 'ask))
365
366 (with-eval-after-load 'gnus-group
367 (setq gnus-permanently-visible-groups "\\(:INBOX$\\|:gnu$\\)"))
368
369 (with-eval-after-load 'gnus-win
370 (setq gnus-use-full-window nil))
371
372 (with-eval-after-load 'gnus-dired
373 (add-hook 'dired-mode-hook 'gnus-dired-mode))
374
375 (with-eval-after-load 'mm-archive
376 (add-to-list
377 'mm-archive-decoders
378 '("application/gzip" nil "gunzip" "-S" ".zip" "-kd" "%f" "-r")))
379
380 (with-eval-after-load 'gnus-start
381 (add-hook 'gnus-after-getting-new-news-hook #'gnus-notifications))
382
383 (with-eval-after-load 'mm-decode
384 (setq
385 ;; mm-attachment-override-types `("text/x-diff" "text/x-patch"
386 ;; ,@mm-attachment-override-types)
387 mm-discouraged-alternatives '("text/html" "text/richtext")
388 mm-decrypt-option 'known
389 mm-verify-option 'known)
390 (add-to-list
391 'mm-inline-media-tests
392 `("application/gzip" mm-archive-dissect-and-inline identity))
393 (add-to-list 'mm-inlined-types "application/gzip" 'append))
394
395 (with-eval-after-load 'mm-uu
396 (when (version< "27" emacs-version)
397 (set-face-attribute 'mm-uu-extract nil :extend t))
398 (when (version< emacs-version "27")
399 (setq mm-uu-diff-groups-regexp ".")))
400
401 (with-eval-after-load 'mml-sec
402 (setq mml-secure-openpgp-encrypt-to-self t
403 mml-secure-openpgp-sign-with-sender t))
404
405 (provide 'bandali-gnus)
406 ;;; bandali-gnus.el ends here